Merge "Support device-specific DeviceStatePolicy"

This commit is contained in:
Kenneth Ford
2022-01-25 02:22:34 +00:00
committed by Android (Google) Code Review
7 changed files with 171 additions and 10 deletions

View File

@@ -4325,6 +4325,10 @@
or empty if the default should be used. -->
<string translatable="false" name="config_deviceSpecificDisplayAreaPolicyProvider"></string>
<!-- Class name of the device specific implementation of DeviceStatePolicy.Provider
or empty if the default should be used. -->
<string translatable="false" name="config_deviceSpecificDeviceStatePolicyProvider"></string>
<!-- Component name of media projection permission dialog -->
<string name="config_mediaProjectionPermissionDialogComponent" translatable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string>

View File

@@ -4667,4 +4667,6 @@
<java-symbol type="bool" name="config_enableSafetyCenter" />
<java-symbol type="string" name="config_deviceManagerUpdater" />
<java-symbol type="string" name="config_deviceSpecificDeviceStatePolicyProvider" />
</resources>

View File

@@ -51,7 +51,6 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.server.DisplayThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.policy.DeviceStatePolicyImpl;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowProcessController;
@@ -142,7 +141,9 @@ public final class DeviceStateManagerService extends SystemService {
private final SparseArray<ProcessRecord> mProcessRecords = new SparseArray<>();
public DeviceStateManagerService(@NonNull Context context) {
this(context, new DeviceStatePolicyImpl(context));
this(context, DeviceStatePolicy.Provider
.fromResources(context.getResources())
.instantiate(context));
}
@VisibleForTesting

View File

@@ -17,6 +17,11 @@
package com.android.server.devicestate;
import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Resources;
import android.text.TextUtils;
import com.android.server.policy.DeviceStatePolicyImpl;
/**
* Interface for the component responsible for supplying the current device state as well as
@@ -24,9 +29,15 @@ import android.annotation.NonNull;
*
* @see DeviceStateManagerService
*/
public interface DeviceStatePolicy {
public abstract class DeviceStatePolicy {
protected final Context mContext;
protected DeviceStatePolicy(@NonNull Context context) {
mContext = context;
}
/** Returns the provider of device states. */
DeviceStateProvider getDeviceStateProvider();
public abstract DeviceStateProvider getDeviceStateProvider();
/**
* Configures the system into the provided state. Guaranteed not to be called again until the
@@ -36,5 +47,58 @@ public interface DeviceStatePolicy {
* @param onComplete a callback that must be triggered once the system has been properly
* configured to match the supplied state.
*/
void configureDeviceForState(int state, @NonNull Runnable onComplete);
public abstract void configureDeviceForState(int state, @NonNull Runnable onComplete);
/** Provider for platform-default device state policy. */
static final class DefaultProvider implements DeviceStatePolicy.Provider {
@Override
public DeviceStatePolicy instantiate(@NonNull Context context) {
return new DeviceStatePolicyImpl(context);
}
}
/**
* Provider for {@link DeviceStatePolicy} instances.
*
* <p>By implementing this interface and overriding the
* {@code config_deviceSpecificDeviceStatePolicyProvider}, a device-specific implementations
* of {@link DeviceStatePolicy} can be supplied.
*/
public interface Provider {
/**
* Instantiates a new {@link DeviceStatePolicy}.
*
* @see DeviceStatePolicy#DeviceStatePolicy
*/
DeviceStatePolicy instantiate(@NonNull Context context);
/**
* Instantiates the device-specific {@link DeviceStatePolicy.Provider}.
*
* Checks the {@code config_deviceSpecificDeviceStatePolicyProvider} resource to see if
* a device specific policy provider has been supplied. If so, returns an instance of that
* provider. If there is no value provided then the method returns the
* {@link DeviceStatePolicy.DefaultProvider}.
*
* An {@link IllegalStateException} is thrown if there is a value provided for that
* resource, but it doesn't correspond to a class that is found.
*/
static Provider fromResources(@NonNull Resources res) {
final String name = res.getString(
com.android.internal.R.string.config_deviceSpecificDeviceStatePolicyProvider);
if (TextUtils.isEmpty(name)) {
return new DeviceStatePolicy.DefaultProvider();
}
try {
return (DeviceStatePolicy.Provider) Class.forName(name).newInstance();
} catch (ReflectiveOperationException | ClassCastException e) {
throw new IllegalStateException("Couldn't instantiate class " + name
+ " for config_deviceSpecificDeviceStatePolicyProvider:"
+ " make sure it has a public zero-argument constructor"
+ " and implements DeviceStatePolicy.Provider", e);
}
}
}
}

View File

@@ -27,12 +27,11 @@ import com.android.server.devicestate.DeviceStateProvider;
*
* @see DeviceStateProviderImpl
*/
public final class DeviceStatePolicyImpl implements DeviceStatePolicy {
private final Context mContext;
public final class DeviceStatePolicyImpl extends DeviceStatePolicy {
private final DeviceStateProvider mProvider;
public DeviceStatePolicyImpl(Context context) {
mContext = context;
public DeviceStatePolicyImpl(@NonNull Context context) {
super(context);
mProvider = DeviceStateProviderImpl.create(mContext);
}

View File

@@ -551,13 +551,14 @@ public final class DeviceStateManagerServiceTest {
Assert.assertTrue(Arrays.equals(expected, actual));
}
private static final class TestDeviceStatePolicy implements DeviceStatePolicy {
private static final class TestDeviceStatePolicy extends DeviceStatePolicy {
private final DeviceStateProvider mProvider;
private int mLastDeviceStateRequestedToConfigure = INVALID_DEVICE_STATE;
private boolean mConfigureBlocked = false;
private Runnable mPendingConfigureCompleteRunnable;
TestDeviceStatePolicy(DeviceStateProvider provider) {
super(InstrumentationRegistry.getContext());
mProvider = provider;
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.devicestate;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
import android.content.Context;
import android.content.res.Resources;
import android.platform.test.annotations.Presubmit;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
/**
* Unit tests for the {@link DeviceStatePolicy.Provider}
* <p/>
* Build/Install/Run:
* <code>atest DeviceStatePolicyProviderTest</code>
*/
@Presubmit
public class DeviceStatePolicyProviderTest {
@Test
public void test_emptyPolicyProvider() {
Assert.assertThat(DeviceStatePolicy.Provider.fromResources(resourcesWithProvider("")),
Matchers.instanceOf(DeviceStatePolicy.DefaultProvider.class));
}
@Test
public void test_nullPolicyProvider() {
Assert.assertThat(DeviceStatePolicy.Provider.fromResources(resourcesWithProvider(null)),
Matchers.instanceOf(DeviceStatePolicy.DefaultProvider.class));
}
@Test
public void test_customPolicyProvider() {
Assert.assertThat(DeviceStatePolicy.Provider.fromResources(resourcesWithProvider(
TestProvider.class.getName())),
Matchers.instanceOf(TestProvider.class));
}
@Test
public void test_badPolicyProvider_notImplementingProviderInterface() {
assertThrows(IllegalStateException.class, () -> {
DeviceStatePolicy.Provider.fromResources(resourcesWithProvider(
Object.class.getName()));
});
}
@Test
public void test_badPolicyProvider_doesntExist() {
assertThrows(IllegalStateException.class, () -> {
DeviceStatePolicy.Provider.fromResources(resourcesWithProvider(
"com.android.devicestate.nonexistent.policy"));
});
}
private static Resources resourcesWithProvider(String provider) {
final Resources mockResources = mock(Resources.class);
when(mockResources.getString(
com.android.internal.R.string.config_deviceSpecificDeviceStatePolicyProvider))
.thenReturn(provider);
return mockResources;
}
// Stub implementation of DeviceStatePolicy.Provider for testing
static class TestProvider implements DeviceStatePolicy.Provider {
@Override
public DeviceStatePolicy instantiate(Context context) {
throw new RuntimeException("test stub");
}
}
}