Add SCREEN_STATE flags to QuickStepContract
The events are sourced from ScreenLifecycle. Bug: 267222890 Test: added unit tests, and manually verified the change Change-Id: Iae8df1f1c4654f37db9a0ec450aa0516405769bc Merged-In: Iae8df1f1c4654f37db9a0ec450aa0516405769bc
This commit is contained in:
@@ -115,6 +115,26 @@ public class QuickStepContract {
|
||||
public static final int SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE = 1 << 26;
|
||||
// Device dreaming state
|
||||
public static final int SYSUI_STATE_DEVICE_DREAMING = 1 << 27;
|
||||
// Whether the screen is currently on. Note that the screen is considered on while turning on,
|
||||
// but not while turning off.
|
||||
public static final int SYSUI_STATE_SCREEN_ON = 1 << 28;
|
||||
// Whether the screen is currently transitioning into the state indicated by
|
||||
// SYSUI_STATE_SCREEN_ON.
|
||||
public static final int SYSUI_STATE_SCREEN_TRANSITION = 1 << 29;
|
||||
|
||||
// Mask for SystemUiStateFlags to isolate SYSUI_STATE_SCREEN_ON and
|
||||
// SYSUI_STATE_SCREEN_TRANSITION, to match SCREEN_STATE_*
|
||||
public static final int SYSUI_STATE_SCREEN_STATE_MASK =
|
||||
SYSUI_STATE_SCREEN_ON | SYSUI_STATE_SCREEN_TRANSITION;
|
||||
// Screen is off.
|
||||
public static final int SCREEN_STATE_OFF = 0;
|
||||
// Screen is on.
|
||||
public static final int SCREEN_STATE_ON = SYSUI_STATE_SCREEN_ON;
|
||||
// Screen is still on, but transitioning to turn off.
|
||||
public static final int SCREEN_STATE_TURNING_OFF = SYSUI_STATE_SCREEN_TRANSITION;
|
||||
// Screen was off and is now turning on.
|
||||
public static final int SCREEN_STATE_TURNING_ON =
|
||||
SYSUI_STATE_SCREEN_TRANSITION | SYSUI_STATE_SCREEN_ON;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({SYSUI_STATE_SCREEN_PINNING,
|
||||
@@ -144,7 +164,9 @@ public class QuickStepContract {
|
||||
SYSUI_STATE_IMMERSIVE_MODE,
|
||||
SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING,
|
||||
SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE,
|
||||
SYSUI_STATE_DEVICE_DREAMING
|
||||
SYSUI_STATE_DEVICE_DREAMING,
|
||||
SYSUI_STATE_SCREEN_ON,
|
||||
SYSUI_STATE_SCREEN_TRANSITION,
|
||||
})
|
||||
public @interface SystemUiStateFlags {}
|
||||
|
||||
@@ -183,6 +205,10 @@ public class QuickStepContract {
|
||||
str.add((flags & SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0
|
||||
? "freeform_active_in_desktop_mode" : "");
|
||||
str.add((flags & SYSUI_STATE_DEVICE_DREAMING) != 0 ? "device_dreaming" : "");
|
||||
str.add("screen_"
|
||||
+ ((flags & SYSUI_STATE_SCREEN_TRANSITION) != 0 ? "turning_" : "")
|
||||
+ ((flags & SYSUI_STATE_SCREEN_ON) != 0 ? "on" : "off"));
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WIN
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_ON;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_TRANSITION;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
|
||||
@@ -121,7 +123,8 @@ import dagger.Lazy;
|
||||
public class OverviewProxyService implements CallbackController<OverviewProxyListener>,
|
||||
NavigationModeController.ModeChangedListener, Dumpable {
|
||||
|
||||
private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
|
||||
@VisibleForTesting
|
||||
static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
|
||||
|
||||
public static final String TAG_OPS = "OverviewProxyService";
|
||||
private static final long BACKOFF_MILLIS = 1000;
|
||||
@@ -548,6 +551,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
|
||||
mUiEventLogger = uiEventLogger;
|
||||
mDisplayTracker = displayTracker;
|
||||
mUnfoldTransitionProgressForwarder = unfoldTransitionProgressForwarder;
|
||||
mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
|
||||
|
||||
dumpManager.registerDumpable(getClass().getSimpleName(), this);
|
||||
|
||||
@@ -596,7 +600,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
|
||||
// Connect to the service
|
||||
updateEnabledState();
|
||||
startConnectionToCurrentUser();
|
||||
mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
|
||||
|
||||
// Listen for assistant changes
|
||||
assistUtils.registerVoiceInteractionSessionListener(mVoiceInteractionSessionListener);
|
||||
@@ -726,10 +729,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
|
||||
return;
|
||||
}
|
||||
mHandler.removeCallbacks(mConnectionRunnable);
|
||||
Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
|
||||
.setPackage(mRecentsComponentName.getPackageName());
|
||||
try {
|
||||
mBound = mContext.bindServiceAsUser(launcherServiceIntent,
|
||||
mBound = mContext.bindServiceAsUser(mQuickStepIntent,
|
||||
mOverviewServiceConnection,
|
||||
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
|
||||
UserHandle.of(mUserTracker.getUserId()));
|
||||
@@ -862,6 +863,11 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
|
||||
*/
|
||||
@Override
|
||||
public void onScreenTurnedOn() {
|
||||
mSysUiState
|
||||
.setFlag(SYSUI_STATE_SCREEN_ON, true)
|
||||
.setFlag(SYSUI_STATE_SCREEN_TRANSITION, false)
|
||||
.commitUpdate(mContext.getDisplayId());
|
||||
|
||||
try {
|
||||
if (mOverviewProxy != null) {
|
||||
mOverviewProxy.onScreenTurnedOn();
|
||||
@@ -873,11 +879,27 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the Launcher that screen turned off.
|
||||
*/
|
||||
@Override
|
||||
public void onScreenTurnedOff() {
|
||||
mSysUiState
|
||||
.setFlag(SYSUI_STATE_SCREEN_ON, false)
|
||||
.setFlag(SYSUI_STATE_SCREEN_TRANSITION, false)
|
||||
.commitUpdate(mContext.getDisplayId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the Launcher that screen is starting to turn on.
|
||||
*/
|
||||
@Override
|
||||
public void onScreenTurningOff() {
|
||||
mSysUiState
|
||||
.setFlag(SYSUI_STATE_SCREEN_ON, false)
|
||||
.setFlag(SYSUI_STATE_SCREEN_TRANSITION, true)
|
||||
.commitUpdate(mContext.getDisplayId());
|
||||
|
||||
try {
|
||||
if (mOverviewProxy != null) {
|
||||
mOverviewProxy.onScreenTurningOff();
|
||||
@@ -894,6 +916,11 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
|
||||
*/
|
||||
@Override
|
||||
public void onScreenTurningOn() {
|
||||
mSysUiState
|
||||
.setFlag(SYSUI_STATE_SCREEN_ON, true)
|
||||
.setFlag(SYSUI_STATE_SCREEN_TRANSITION, true)
|
||||
.commitUpdate(mContext.getDisplayId());
|
||||
|
||||
try {
|
||||
if (mOverviewProxy != null) {
|
||||
mOverviewProxy.onScreenTurningOn();
|
||||
@@ -1005,4 +1032,21 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
|
||||
default void onAssistantGestureCompletion(float velocity) {}
|
||||
default void startAssistant(Bundle bundle) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down this service at the end of a testcase.
|
||||
* <p>
|
||||
* The in-production service is never shuts down, and it was not designed with testing in mind.
|
||||
* This unregisters the mechanisms by which the service will be revived after a testcase.
|
||||
* <p>
|
||||
* NOTE: This is a stop-gap introduced when first added some tests to this class. It should
|
||||
* probably be replaced by proper lifecycle management on this class.
|
||||
*/
|
||||
@VisibleForTesting()
|
||||
void shutdownForTest() {
|
||||
mContext.unregisterReceiver(mLauncherStateChangedReceiver);
|
||||
mIsEnabled = false;
|
||||
mHandler.removeCallbacks(mConnectionRunnable);
|
||||
disconnectFromLauncherService();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.recents
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.ResolveInfo
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableContext
|
||||
import android.testing.TestableLooper
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.internal.app.AssistUtils
|
||||
import com.android.internal.logging.UiEventLogger
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
|
||||
import com.android.systemui.keyguard.ScreenLifecycle
|
||||
import com.android.systemui.model.SysUiState
|
||||
import com.android.systemui.navigationbar.NavigationBarController
|
||||
import com.android.systemui.navigationbar.NavigationModeController
|
||||
import com.android.systemui.recents.OverviewProxyService.ACTION_QUICKSTEP
|
||||
import com.android.systemui.settings.FakeDisplayTracker
|
||||
import com.android.systemui.settings.UserTracker
|
||||
import com.android.systemui.shared.recents.IOverviewProxy
|
||||
import com.android.systemui.shared.system.QuickStepContract.SCREEN_STATE_OFF
|
||||
import com.android.systemui.shared.system.QuickStepContract.SCREEN_STATE_ON
|
||||
import com.android.systemui.shared.system.QuickStepContract.SCREEN_STATE_TURNING_OFF
|
||||
import com.android.systemui.shared.system.QuickStepContract.SCREEN_STATE_TURNING_ON
|
||||
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_STATE_MASK
|
||||
import com.android.systemui.statusbar.CommandQueue
|
||||
import com.android.systemui.statusbar.NotificationShadeWindowController
|
||||
import com.android.systemui.statusbar.phone.CentralSurfaces
|
||||
import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.android.wm.shell.sysui.ShellInterface
|
||||
import com.google.common.util.concurrent.MoreExecutors
|
||||
import dagger.Lazy
|
||||
import java.util.Optional
|
||||
import java.util.concurrent.Executor
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentMatchers
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.any
|
||||
import org.mockito.Mockito.anyInt
|
||||
import org.mockito.Mockito.intThat
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@TestableLooper.RunWithLooper(setAsMainLooper = true)
|
||||
class OverviewProxyServiceTest : SysuiTestCase() {
|
||||
|
||||
@Main private val executor: Executor = MoreExecutors.directExecutor()
|
||||
|
||||
private lateinit var subject: OverviewProxyService
|
||||
private val dumpManager = DumpManager()
|
||||
private val displayTracker = FakeDisplayTracker(mContext)
|
||||
private val sysUiState = SysUiState(displayTracker)
|
||||
private val screenLifecycle = ScreenLifecycle(dumpManager)
|
||||
|
||||
@Mock private lateinit var overviewProxy: IOverviewProxy.Stub
|
||||
@Mock private lateinit var packageManager: PackageManager
|
||||
|
||||
// The following mocks belong to not-yet-tested parts of OverviewProxyService.
|
||||
@Mock private lateinit var commandQueue: CommandQueue
|
||||
@Mock private lateinit var shellInterface: ShellInterface
|
||||
@Mock private lateinit var navBarController: NavigationBarController
|
||||
@Mock private lateinit var centralSurfaces: CentralSurfaces
|
||||
@Mock private lateinit var navModeController: NavigationModeController
|
||||
@Mock private lateinit var statusBarWinController: NotificationShadeWindowController
|
||||
@Mock private lateinit var userTracker: UserTracker
|
||||
@Mock private lateinit var uiEventLogger: UiEventLogger
|
||||
@Mock private lateinit var sysuiUnlockAnimationController: KeyguardUnlockAnimationController
|
||||
@Mock private lateinit var assistUtils: AssistUtils
|
||||
@Mock
|
||||
private lateinit var unfoldTransitionProgressForwarder:
|
||||
Optional<UnfoldTransitionProgressForwarder>
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
val serviceComponent = ComponentName("test_package", "service_provider")
|
||||
context.addMockService(serviceComponent, overviewProxy)
|
||||
context.addMockServiceResolver(
|
||||
TestableContext.MockServiceResolver {
|
||||
if (it.action == ACTION_QUICKSTEP) serviceComponent else null
|
||||
}
|
||||
)
|
||||
whenever(overviewProxy.queryLocalInterface(ArgumentMatchers.anyString()))
|
||||
.thenReturn(overviewProxy)
|
||||
whenever(overviewProxy.asBinder()).thenReturn(overviewProxy)
|
||||
|
||||
// packageManager.resolveServiceAsUser has to return non-null for
|
||||
// OverviewProxyService#isEnabled to become true.
|
||||
context.setMockPackageManager(packageManager)
|
||||
whenever(packageManager.resolveServiceAsUser(any(), anyInt(), anyInt()))
|
||||
.thenReturn(mock(ResolveInfo::class.java))
|
||||
|
||||
subject =
|
||||
OverviewProxyService(
|
||||
context,
|
||||
executor,
|
||||
commandQueue,
|
||||
shellInterface,
|
||||
Lazy { navBarController },
|
||||
Lazy { Optional.of(centralSurfaces) },
|
||||
navModeController,
|
||||
statusBarWinController,
|
||||
sysUiState,
|
||||
userTracker,
|
||||
screenLifecycle,
|
||||
uiEventLogger,
|
||||
displayTracker,
|
||||
sysuiUnlockAnimationController,
|
||||
assistUtils,
|
||||
dumpManager,
|
||||
unfoldTransitionProgressForwarder
|
||||
)
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
subject.shutdownForTest()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ScreenLifecycle - screenTurnedOn triggers SysUI state flag changes `() {
|
||||
screenLifecycle.dispatchScreenTurnedOn()
|
||||
|
||||
verify(overviewProxy)
|
||||
.onSystemUiStateChanged(
|
||||
intThat { it and SYSUI_STATE_SCREEN_STATE_MASK == SCREEN_STATE_ON }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ScreenLifecycle - screenTurningOn triggers SysUI state flag changes `() {
|
||||
screenLifecycle.dispatchScreenTurningOn()
|
||||
|
||||
verify(overviewProxy)
|
||||
.onSystemUiStateChanged(
|
||||
intThat { it and SYSUI_STATE_SCREEN_STATE_MASK == SCREEN_STATE_TURNING_ON }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ScreenLifecycle - screenTurnedOff triggers SysUI state flag changes `() {
|
||||
screenLifecycle.dispatchScreenTurnedOff()
|
||||
|
||||
verify(overviewProxy)
|
||||
.onSystemUiStateChanged(
|
||||
intThat { it and SYSUI_STATE_SCREEN_STATE_MASK == SCREEN_STATE_OFF }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ScreenLifecycle - screenTurningOff triggers SysUI state flag changes `() {
|
||||
screenLifecycle.dispatchScreenTurningOff()
|
||||
|
||||
verify(overviewProxy)
|
||||
.onSystemUiStateChanged(
|
||||
intThat { it and SYSUI_STATE_SCREEN_STATE_MASK == SCREEN_STATE_TURNING_OFF }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -33,11 +33,15 @@ import android.provider.Settings;
|
||||
import android.util.ArrayMap;
|
||||
import android.view.LayoutInflater;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.rules.TestWatcher;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* A ContextWrapper with utilities specifically designed to make Testing easier.
|
||||
*
|
||||
@@ -61,6 +65,7 @@ public class TestableContext extends ContextWrapper implements TestRule {
|
||||
private final TestableContentResolver mTestableContentResolver;
|
||||
private final TestableSettingsProvider mSettingsProvider;
|
||||
|
||||
private ArrayList<MockServiceResolver> mMockServiceResolvers;
|
||||
private ArrayMap<String, Object> mMockSystemServices;
|
||||
private ArrayMap<ComponentName, IBinder> mMockServices;
|
||||
private ArrayMap<ServiceConnection, ComponentName> mActiveServices;
|
||||
@@ -214,25 +219,54 @@ public class TestableContext extends ContextWrapper implements TestRule {
|
||||
/**
|
||||
* Adds a mock service to be connected to by a bindService call.
|
||||
* <p>
|
||||
* Normally a TestableContext will pass through all bind requests to the base context
|
||||
* but when addMockService has been called for a ComponentName being bound, then
|
||||
* TestableContext will immediately trigger a {@link ServiceConnection#onServiceConnected}
|
||||
* with the specified service, and will call {@link ServiceConnection#onServiceDisconnected}
|
||||
* when the service is unbound.
|
||||
* Normally a TestableContext will pass through all bind requests to the base context
|
||||
* but when addMockService has been called for a ComponentName being bound, then
|
||||
* TestableContext will immediately trigger a {@link ServiceConnection#onServiceConnected}
|
||||
* with the specified service, and will call {@link ServiceConnection#onServiceDisconnected}
|
||||
* when the service is unbound.
|
||||
* </p>
|
||||
*
|
||||
* @see #addMockServiceResolver(MockServiceResolver) for custom resolution of service Intents to
|
||||
* ComponentNames
|
||||
*/
|
||||
public void addMockService(ComponentName component, IBinder service) {
|
||||
if (mMockServices == null) mMockServices = new ArrayMap<>();
|
||||
mMockServices.put(component, service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy to resolve a service {@link Intent} to a mock service {@link ComponentName}.
|
||||
*/
|
||||
public interface MockServiceResolver {
|
||||
@Nullable
|
||||
ComponentName resolve(Intent service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a strategy to resolve service intents to registered mock services.
|
||||
* <p>
|
||||
* The result of the first {@link MockServiceResolver} to return a non-null
|
||||
* {@link ComponentName} is used to look up a mock service. The mock service must be registered
|
||||
* via {@link #addMockService(ComponentName, IBinder)} separately, using the same component
|
||||
* name.
|
||||
*
|
||||
* If none of the resolvers return a non-null value, or the first returned component name
|
||||
* does not link to a registered mock service, the bind requests are passed to the base context
|
||||
*
|
||||
* The resolvers are queried in order of registration.
|
||||
*/
|
||||
public void addMockServiceResolver(MockServiceResolver resolver) {
|
||||
if (mMockServiceResolvers == null) mMockServiceResolvers = new ArrayList<>();
|
||||
mMockServiceResolvers.add(resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #addMockService(ComponentName, IBinder)
|
||||
*/
|
||||
@Override
|
||||
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
|
||||
if (mService != null) mService.getLeakInfo(conn).addAllocation(new Throwable());
|
||||
if (checkMocks(service.getComponent(), conn)) return true;
|
||||
if (checkMocks(service, conn)) return true;
|
||||
return super.bindService(service, conn, flags);
|
||||
}
|
||||
|
||||
@@ -243,7 +277,7 @@ public class TestableContext extends ContextWrapper implements TestRule {
|
||||
public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
|
||||
Handler handler, UserHandle user) {
|
||||
if (mService != null) mService.getLeakInfo(conn).addAllocation(new Throwable());
|
||||
if (checkMocks(service.getComponent(), conn)) return true;
|
||||
if (checkMocks(service, conn)) return true;
|
||||
return super.bindServiceAsUser(service, conn, flags, handler, user);
|
||||
}
|
||||
|
||||
@@ -254,18 +288,36 @@ public class TestableContext extends ContextWrapper implements TestRule {
|
||||
public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
|
||||
UserHandle user) {
|
||||
if (mService != null) mService.getLeakInfo(conn).addAllocation(new Throwable());
|
||||
if (checkMocks(service.getComponent(), conn)) return true;
|
||||
if (checkMocks(service, conn)) return true;
|
||||
return super.bindServiceAsUser(service, conn, flags, user);
|
||||
}
|
||||
|
||||
private boolean checkMocks(ComponentName component, ServiceConnection conn) {
|
||||
if (mMockServices != null && component != null && mMockServices.containsKey(component)) {
|
||||
if (mActiveServices == null) mActiveServices = new ArrayMap<>();
|
||||
mActiveServices.put(conn, component);
|
||||
conn.onServiceConnected(component, mMockServices.get(component));
|
||||
return true;
|
||||
private boolean checkMocks(Intent service, ServiceConnection conn) {
|
||||
if (mMockServices == null) return false;
|
||||
|
||||
ComponentName serviceComponent = resolveMockServiceComponent(service);
|
||||
if (serviceComponent == null) return false;
|
||||
|
||||
IBinder serviceImpl = mMockServices.get(serviceComponent);
|
||||
if (serviceImpl == null) return false;
|
||||
|
||||
if (mActiveServices == null) mActiveServices = new ArrayMap<>();
|
||||
mActiveServices.put(conn, serviceComponent);
|
||||
conn.onServiceConnected(serviceComponent, serviceImpl);
|
||||
return true;
|
||||
}
|
||||
|
||||
private ComponentName resolveMockServiceComponent(Intent service) {
|
||||
ComponentName specifiedComponentName = service.getComponent();
|
||||
if (specifiedComponentName != null) return specifiedComponentName;
|
||||
|
||||
if (mMockServiceResolvers == null) return null;
|
||||
|
||||
for (MockServiceResolver resolver : mMockServiceResolvers) {
|
||||
ComponentName resolvedComponent = resolver.resolve(service);
|
||||
if (resolvedComponent != null) return resolvedComponent;
|
||||
}
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user