• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.compat.testing;
18 
19 import android.Manifest;
20 import android.app.Instrumentation;
21 import android.app.UiAutomation;
22 import android.compat.Compatibility;
23 import android.compat.Compatibility.ChangeConfig;
24 import android.content.Context;
25 import android.os.RemoteException;
26 import android.os.ServiceManager;
27 
28 import androidx.test.platform.app.InstrumentationRegistry;
29 
30 
31 import com.android.internal.compat.CompatibilityChangeConfig;
32 import com.android.internal.compat.IPlatformCompat;
33 
34 import libcore.junit.util.compat.CoreCompatChangeRule;
35 
36 import org.junit.runners.model.Statement;
37 
38 /**
39  * Allows tests to specify the which change to disable.
40  *
41  * <p>To use add the following to the test class. It will only change the behavior of a test method
42  * if it is annotated with
43  * {@link libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges} and/or
44  * {@link libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges}.
45  * </p>
46  * <pre>
47  * @Rule
48  * public TestRule compatChangeRule = new PlatformCompatChangeRule();
49  * </pre>
50  *
51  * <p>Each test method that needs to disable a specific change needs to be annotated
52  * with {@link libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges} and/or
53  * {@link libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges} specifying the change
54  * id. e.g.:
55  * </p>
56  * <pre>
57  *   @Test
58  *   @DisableCompatChanges({42})
59  *   public void testAsIfChange42Disabled() {
60  *     // check behavior
61  *   }
62  *
63  *   @Test
64  *   @EnableCompatChanges({42})
65  *   public void testAsIfChange42Enabled() {
66  *     // check behavior
67  *
68  * </pre>
69  */
70 public class PlatformCompatChangeRule extends CoreCompatChangeRule {
71 
72     @Override
createStatementForConfig(final Statement statement, ChangeConfig config)73     protected Statement createStatementForConfig(final Statement statement, ChangeConfig config) {
74         return new CompatChangeStatement(statement, config);
75     }
76 
77 
78     private static class CompatChangeStatement extends Statement {
79         private final Statement mTestStatement;
80         private final ChangeConfig mConfig;
81 
CompatChangeStatement(Statement testStatement, ChangeConfig config)82         private CompatChangeStatement(Statement testStatement, ChangeConfig config) {
83             this.mTestStatement = testStatement;
84             this.mConfig = config;
85         }
86 
87         @Override
evaluate()88         public void evaluate() throws Throwable {
89             Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
90             UiAutomation uiAutomation = instrumentation.getUiAutomation();
91             String packageName = instrumentation.getTargetContext().getPackageName();
92             IPlatformCompat platformCompat = IPlatformCompat.Stub
93                     .asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
94             if (platformCompat == null) {
95                 throw new IllegalStateException("Could not get IPlatformCompat service!");
96             }
97             adoptShellPermissions(uiAutomation);
98             Compatibility.setOverrides(mConfig);
99             try {
100                 platformCompat.setOverridesForTest(new CompatibilityChangeConfig(mConfig),
101                         packageName);
102                 try {
103                     mTestStatement.evaluate();
104                 } finally {
105                     adoptShellPermissions(uiAutomation);
106                     platformCompat.clearOverridesForTest(packageName);
107                 }
108             } catch (RemoteException e) {
109                 throw new RuntimeException("Could not call IPlatformCompat binder method!", e);
110             } finally {
111                 uiAutomation.dropShellPermissionIdentity();
112                 Compatibility.clearOverrides();
113             }
114         }
115 
adoptShellPermissions(UiAutomation uiAutomation)116         private static void adoptShellPermissions(UiAutomation uiAutomation) {
117             uiAutomation.adoptShellPermissionIdentity(
118                     Manifest.permission.LOG_COMPAT_CHANGE,
119                     Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG,
120                     Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD,
121                     Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
122                     Manifest.permission.INTERACT_ACROSS_USERS_FULL);
123         }
124     }
125 }
126