Generate full Activity class instead of hardcoding.
Test: atest TestAppTest
Test: atest NeneTest
Test: atest CtsDevicePolicyTestCases
Bug: 198407955
Change-Id: I4076bd9703556e10812bdc9fad158d0b93249263
diff --git a/common/device-side/bedstead/nene/Android.bp b/common/device-side/bedstead/nene/Android.bp
index 4e249bf..21809bb 100644
--- a/common/device-side/bedstead/nene/Android.bp
+++ b/common/device-side/bedstead/nene/Android.bp
@@ -13,7 +13,8 @@
static_libs: [
"compatibility-device-util-axt",
"guava",
- "Queryable"
+ "Queryable",
+ "RemoteFrameworkClasses"
],
min_sdk_version: "27"
}
@@ -28,7 +29,8 @@
static_libs: [
"compatibility-device-util-axt",
"guava",
- "Queryable"
+ "Queryable",
+ "RemoteFrameworkClasses"
],
min_sdk_version: "27"
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/Activities.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/Activities.java
index a651aca..821176d 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/Activities.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/Activities.java
@@ -40,15 +40,9 @@
private Activities() {
}
- /**
- * Wrap the given {@link NeneActivityDirect} to use Nene APIs.
- */
- public Activity<NeneActivityDirect> wrap(NeneActivity activity) {
- return new Activity<>(activity, activity);
- }
/**
- * Wrap the given {@link NeneActivityDirect} subclass to use Nene APIs.
+ * Wrap the given {@link NeneActivity} subclass to use Nene APIs.
*/
public <E extends NeneActivity> Activity<E> wrap(Class<E> clazz, E activity) {
return new Activity<>(activity, activity);
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/ActivityWrapper.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/ActivityWrapper.java
index 802366d..01fb496 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/ActivityWrapper.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/ActivityWrapper.java
@@ -17,57 +17,18 @@
package com.android.bedstead.nene.activities;
import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.Bundle;
+import android.app.RemoteActivityImpl;
import android.os.UserHandle;
-class ActivityWrapper implements NeneActivity {
-
- private final Activity mActivity;
+class ActivityWrapper extends RemoteActivityImpl implements NeneActivity {
ActivityWrapper(Activity activity) {
- mActivity = activity;
- }
-
- @Override
- public ComponentName getComponentName() {
- return mActivity.getComponentName();
+ super(activity);
}
@Override
public UserHandle getUser() {
- // Assuming if we have an Activity it's on the current user
+ // Assuming if we have an Activity it's on the instrumented user
return android.os.Process.myUserHandle();
}
-
- @Override
- public void startLockTask() {
- mActivity.startLockTask();
- }
-
- @Override
- public void stopLockTask() {
- mActivity.stopLockTask();
- }
-
- @Override
- public void finish() {
- mActivity.finish();
- }
-
- @Override
- public boolean isFinishing() {
- return mActivity.isFinishing();
- }
-
- @Override
- public void startActivity(Intent intent) {
- mActivity.startActivity(intent);
- }
-
- @Override
- public void startActivity(Intent intent, Bundle options) {
- mActivity.startActivity(intent, options);
- }
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivity.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivity.java
index f8bfeef..9a5a0ea 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivity.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivity.java
@@ -16,13 +16,14 @@
package com.android.bedstead.nene.activities;
+import android.app.RemoteActivity;
import android.os.UserHandle;
/**
- * Additional methods which are not direct wrappes of {@link Activity}.
+ * Additional methods which are not direct wrappers of {@link Activity}.
*/
-public interface NeneActivity extends NeneActivityDirect {
+public interface NeneActivity extends RemoteActivity {
- /** See {@link android.app.Activity#getUser()}. */
+ /** Get the user the Activity is running on. */
UserHandle getUser();
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivityDirect.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivityDirect.java
deleted file mode 100644
index 6207779..0000000
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/activities/NeneActivityDirect.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.bedstead.nene.activities;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.UserHandle;
-
-/**
- * Interface for use by classes which are able to be used in Nene activity test apis.
- *
- * <p>Methods on this interface should match exactly methods on {@link Activity}.
- */
-public interface NeneActivityDirect {
- /** See {@link Activity#getComponentName}. */
- ComponentName getComponentName();
-
- /** See {@link Activity#startLockTask}. */
- void startLockTask();
-
- /** See {@link Activity#stopLockTask}. */
- void stopLockTask();
-
- /** See {@link Activity#finish()}. */
- void finish();
-
- /** See {@link Activity#isFinishing}. */
- boolean isFinishing();
-
- /** See {@link Activity#startActivity}. */
- void startActivity(Intent intent);
-
- /** See {@link Activity#startActivity}. */
- void startActivity(Intent intent, Bundle options);
-}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/PermissionContextImpl.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/PermissionContextImpl.java
index f7f3a59..3442035 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/PermissionContextImpl.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/PermissionContextImpl.java
@@ -74,6 +74,18 @@
}
/**
+ * See {@link Permissions#withPermissionOnVersionAtLeast(int, String...)}
+ */
+ public PermissionContextImpl withPermissionOnVersionAtLeast(
+ int sdkVersion, String... permissions) {
+ if (Versions.meetsMinimumSdkVersionRequirement(sdkVersion)) {
+ return withPermission(permissions);
+ }
+
+ return this;
+ }
+
+ /**
* See {@link Permissions#withoutPermission(String...)}
*/
public PermissionContextImpl withoutPermission(String... permissions) {
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/Permissions.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/Permissions.java
index 88aef56..2806d25 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/Permissions.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/Permissions.java
@@ -129,6 +129,29 @@
/**
* Enter a {@link PermissionContext} where the given permissions are granted only when running
+ * on the given version or above.
+ *
+ * <p>If the permissions cannot be granted, and are not already granted, an exception will be
+ * thrown.
+ *
+ * <p>If the version does not match, the permission context will not change.
+ */
+ public PermissionContextImpl withPermissionOnVersionAtLeast(
+ int minSdkVersion, String... permissions) {
+ if (mPermissionContexts.isEmpty()) {
+ recordExistingPermissions();
+ }
+
+ PermissionContextImpl permissionContext = new PermissionContextImpl(this);
+ mPermissionContexts.add(permissionContext);
+
+ permissionContext.withPermissionOnVersionAtLeast(minSdkVersion, permissions);
+
+ return permissionContext;
+ }
+
+ /**
+ * Enter a {@link PermissionContext} where the given permissions are granted only when running
* on the given version.
*
* <p>If the permissions cannot be granted, and are not already granted, an exception will be
diff --git a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageTest.java b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageTest.java
index e6f0f84..e582617 100644
--- a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageTest.java
+++ b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageTest.java
@@ -89,7 +89,7 @@
@BeforeClass
public static void setupClass() throws Exception {
try (PermissionContext p = TestApis.permissions()
- .withPermissionOnVersion(R, MANAGE_EXTERNAL_STORAGE)) {
+ .withPermissionOnVersionAtLeast(R, MANAGE_EXTERNAL_STORAGE)) {
sTestApp.writeApkFile(sTestAppApkFile);
}
}
@@ -97,7 +97,7 @@
@AfterClass
public static void teardownClass() throws Exception {
try (PermissionContext p = TestApis.permissions()
- .withPermissionOnVersion(R, MANAGE_EXTERNAL_STORAGE)) {
+ .withPermissionOnVersionAtLeast(R, MANAGE_EXTERNAL_STORAGE)) {
sTestAppApkFile.delete();
}
}
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Apis.java b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Apis.java
index 57b31c5..0f2900e2 100644
--- a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Apis.java
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Apis.java
@@ -28,6 +28,9 @@
import java.util.Set;
import java.util.stream.Collectors;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
@@ -39,20 +42,19 @@
private static final String[] API_FILES =
{"current.txt", "test-current.txt", "wifi-current.txt"};
- private static final Set<String> API_TXTS = initialiseApiTxts();
+ private static final Map<String, String> API_TXTS = initialiseApiTxts();
private static final Map<String, Apis> sPackageToApi = new HashMap<>();
- private static Set<String> initialiseApiTxts() {
+ private static Map<String, String> initialiseApiTxts() {
return Arrays.stream(API_FILES)
- .map(f -> {
+ .collect(Collectors.toMap(f -> f, f -> {
try {
return Resources.toString(Processor.class.getResource("/apis/" + f),
StandardCharsets.UTF_8);
} catch (IOException e) {
throw new IllegalStateException("Could not read file " + f);
}
- })
- .collect(Collectors.toSet());
+ }));
}
/**
@@ -62,30 +64,53 @@
if (sPackageToApi.containsKey(className)) {
return sPackageToApi.get(className);
}
-
ImmutableSet.Builder<MethodSignature> methods = ImmutableSet.builder();
- for (String apiTxt : API_TXTS) {
- methods.addAll(parseApiTxt(apiTxt, className, types, elements));
+ Set<String> parents = new HashSet<>();
+ findParents(parents, className, elements);
+ for (String c : parents) {
+ for (Map.Entry<String, String> apiTxt : API_TXTS.entrySet()) {
+ methods.addAll(
+ parseApiTxt(apiTxt.getKey(), apiTxt.getValue(), c, types, elements));
+ }
}
return new Apis(methods.build());
}
+ private static void findParents(Set<String> parents, String className, Elements elements) {
+ parents.add(className);
+
+ if (className.equals("java.lang.Object")) {
+ return;
+ }
+
+ TypeElement element = elements.getTypeElement(className);
+ System.out.println("Checking " + className + " got " + element);
+
+ TypeMirror superClass = element.getSuperclass();
+ if (!superClass.getKind().equals(TypeKind.NONE)) {
+ findParents(parents, superClass.toString(), elements);
+ }
+
+ element.getInterfaces().stream().map(TypeMirror::toString)
+ .forEach(c -> findParents(parents, c, elements));
+ }
+
private static Set<MethodSignature> parseApiTxt(
- String apiTxt, String className, Types types, Elements elements) {
+ String filename, String apiTxt, String className, Types types, Elements elements) {
int separatorPosition = className.lastIndexOf(".");
String packageName = className.substring(0, separatorPosition);
String simpleClassName = className.substring(separatorPosition + 1);
String[] packageSplit = apiTxt.split("package " + packageName + " \\{", 2);
if (packageSplit.length < 2) {
- System.out.println("Package " + packageName + " not in file");
+ System.out.println("Package " + packageName + " not in file " + filename);
// Package not in this file
return new HashSet<>();
}
- String[] classSplit = packageSplit[1].split("class " + simpleClassName + " \\{", 2);
+ String[] classSplit = packageSplit[1].split("class " + simpleClassName + " .*?\n", 2);
if (classSplit.length < 2) {
- System.out.println("Class " + simpleClassName + " not in file");
+ System.out.println("Class " + simpleClassName + " not in file " + filename);
// Class not in this file
return new HashSet<>();
}
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/MethodSignature.java b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/MethodSignature.java
index a1f950a..d6f0ee0 100644
--- a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/MethodSignature.java
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/MethodSignature.java
@@ -76,20 +76,24 @@
string = string.replaceAll("@.+? ", "");
String[] parts = string.split(" ", 2);
- Visibility visibility = Visibility.valueOf(parts[0].toUpperCase());
+ Visibility visibility;
+ try {
+ visibility = Visibility.valueOf(parts[0].toUpperCase());
+ } catch (IllegalArgumentException e) {
+ throw new IllegalStateException("Error finding visibility in string " + string);
+ }
string = parts[1];
parts = string.split(" ", 2);
TypeMirror returnType;
- if (parts[0].equals("abstract")) {
+ if (parts[0].equals("abstract") || parts[0].equals("final")) {
// Doesn't matter - we're wrapping anyway
string = parts[1];
parts = string.split(" ", 2);
- returnType = typeForString(parts[0], types, elements);
- } else {
- returnType = typeForString(parts[0], types, elements);
}
+ returnType = typeForString(parts[0], types, elements);
+
string = parts[1];
parts = string.split("\\(", 2);
String methodName = parts[0];
@@ -97,11 +101,18 @@
parts = string.split("\\)", 2);
// Remove generic types as we don't need to care about them at this point
String parametersString = parts[0].replaceAll("<.*>", "");
- List<TypeMirror> parameters = Arrays.stream(parametersString.split(","))
- .map(String::trim)
- .filter(t -> !t.isEmpty())
- .map(t -> typeForString(t, types, elements))
- .collect(Collectors.toList());
+ // Remove varargs
+ parametersString = parametersString.replaceAll("\\.\\.\\.", "");
+ List<TypeMirror> parameters;
+ try {
+ parameters = Arrays.stream(parametersString.split(","))
+ .map(String::trim)
+ .filter(t -> !t.isEmpty())
+ .map(t -> typeForString(t, types, elements))
+ .collect(Collectors.toList());
+ } catch (IllegalStateException e) {
+ throw new IllegalStateException("Error parsing types from string " + parametersString);
+ }
string = parts[1];
Set<TypeMirror> exceptions = new HashSet<>();
if (string.contains("throws")) {
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java
index ba321d5..9ce9014 100644
--- a/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/main/java/com/android/bedstead/remoteframeworkclasses/processor/Processor.java
@@ -34,6 +34,7 @@
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@@ -57,7 +58,7 @@
*
* <p>This is started by including the {@link RemoteFrameworkClasses} annotation.
*
- * <p>For each entry in {@code SYSTEM_SERVICES} this will generate an interface including all public
+ * <p>For each entry in {@code FRAMEWORK_CLASSES} this will generate an interface including all public
* and test APIs with the {@code CrossUser} annotation. This interface will be named the same as the
* framework class except with a prefix of "Remote", and will be in the same package.
*
@@ -70,7 +71,7 @@
@AutoService(javax.annotation.processing.Processor.class)
public final class Processor extends AbstractProcessor {
- private static final String[] SYSTEM_SERVICES = {
+ private static final String[] FRAMEWORK_CLASSES = {
"android.app.admin.DevicePolicyManager",
"android.net.wifi.WifiManager",
"android.os.HardwarePropertiesManager",
@@ -78,7 +79,8 @@
"android.content.pm.PackageManager",
"android.content.pm.CrossProfileApps",
"android.content.pm.LauncherApps",
- "android.accounts.AccountManager"
+ "android.accounts.AccountManager",
+ "android.app.Activity"
};
private static final String PARENT_PROFILE_INSTANCE =
@@ -297,7 +299,170 @@
"public android.os.Bundle isCredentialsUpdateSuggested(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, String) throws android.accounts.NetworkErrorException",
"public android.accounts.AccountManagerFuture<java.lang.Boolean> isCredentialsUpdateSuggested(android.accounts.Account, String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler)",
"public android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler)",
- "public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, @Size(min=1) String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler)"
+ "public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, @Size(min=1) String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler)",
+
+ // Activity
+
+ // Uses android.view.View
+ "public void addContentView(android.view.View, android.view.ViewGroup.LayoutParams)",
+ "@Nullable public android.view.View getCurrentFocus()",
+ "@Nullable public android.view.View onCreatePanelView(int)",
+ "@Nullable public android.view.View onCreateView(@NonNull String, @NonNull android.content.Context, @NonNull android.util.AttributeSet)",
+ "@Nullable public android.view.View onCreateView(@Nullable android.view.View, @NonNull String, @NonNull android.content.Context, @NonNull android.util.AttributeSet)",
+ "public boolean onPreparePanel(int, @Nullable android.view.View, @NonNull android.view.Menu)",
+ "public void openContextMenu(android.view.View)",
+ "public void registerForContextMenu(android.view.View)",
+ "public void setContentView(android.view.View)",
+ "public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams)",
+ "public void unregisterForContextMenu(android.view.View)",
+
+ // Uses java.io.FileDescriptor
+ "public void dump(@NonNull String, @Nullable java.io.FileDescriptor, @NonNull java.io.PrintWriter, @Nullable String[])",
+
+ // Uses android.app.Activity
+ "@Deprecated public void finishActivityFromChild(@NonNull android.app.Activity, int)",
+ "@Deprecated public void finishFromChild(android.app.Activity)",
+ "public final android.app.Activity getParent()",
+ "@Deprecated public boolean navigateUpToFromChild(android.app.Activity, android.content.Intent)",
+ "protected void onChildTitleChanged(android.app.Activity, CharSequence)",
+ "@Deprecated public boolean onNavigateUpFromChild(android.app.Activity)",
+ "@Deprecated public void startActivityFromChild(@NonNull android.app.Activity, @RequiresPermission android.content.Intent, int)",
+ "@Deprecated public void startActivityFromChild(@NonNull android.app.Activity, @RequiresPermission android.content.Intent, int, @Nullable android.os.Bundle)",
+ "@Deprecated public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException",
+ "@Deprecated public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int, @Nullable android.os.Bundle) throws android.content.IntentSender.SendIntentException",
+
+ // Uses android.app.ActionBar
+ "@Nullable public android.app.ActionBar getActionBar()",
+
+ // Uses android.app.Application
+ "public final android.app.Application getApplication()",
+
+ // Uses android.app.Fragment
+ "@Deprecated public void onAttachFragment(android.app.Fragment)",
+ "@Deprecated public void startActivityFromFragment(@NonNull android.app.Fragment, @RequiresPermission android.content.Intent, int)",
+ "@Deprecated public void startActivityFromFragment(@NonNull android.app.Fragment, @RequiresPermission android.content.Intent, int, @Nullable android.os.Bundle)",
+
+ // Uses android.app.FragmentManager
+ "@Deprecated public android.app.FragmentManager getFragmentManager()",
+
+ // Uses android.transition.Scene
+ "public android.transition.Scene getContentScene()",
+
+ // Uses android.transition.TransitionManager
+ "public android.transition.TransitionManager getContentTransitionManager()",
+ "public void setContentTransitionManager(android.transition.TransitionManager)",
+
+ // Uses Object
+ "@Nullable public Object getLastNonConfigurationInstance()",
+ "public Object onRetainNonConfigurationInstance()",
+
+ // Uses android.view.LayoutInflater
+ "@NonNull public android.view.LayoutInflater getLayoutInflater()",
+
+ // Uses android.view.MenuInflater
+ "@NonNull public android.view.MenuInflater getMenuInflater()",
+
+ // Uses android.app.LoaderManager
+ "@Deprecated public android.app.LoaderManager getLoaderManager()",
+
+ // Uses android.media.session.MediaController
+ "public final android.media.session.MediaController getMediaController()",
+
+ // Uses android.content.SharedPreferences
+ "public android.content.SharedPreferences getPreferences(int)",
+
+ // Uses android.view.SearchEvent
+ "public final android.view.SearchEvent getSearchEvent()",
+
+ // Uses android.window.SplashScreen
+ "@NonNull public final android.window.SplashScreen getSplashScreen()",
+
+ // Uses android.app.VoiceInteractor
+ "public android.app.VoiceInteractor getVoiceInteractor()",
+
+ // Uses android.view.Window
+ "public android.view.Window getWindow()",
+
+ // Uses android.view.WindowManager
+ "public android.view.WindowManager getWindowManager()",
+
+ // Uses android.database.Cursor
+ "@Deprecated public final android.database.Cursor managedQuery(android.net.Uri, String[], String, String[], String)",
+ "@Deprecated public void startManagingCursor(android.database.Cursor)",
+ "@Deprecated public void stopManagingCursor(android.database.Cursor)",
+
+ // Uses android.view.ActionMode
+ "@CallSuper public void onActionModeFinished(android.view.ActionMode)",
+ "@CallSuper public void onActionModeStarted(android.view.ActionMode)",
+ "@Nullable public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback)",
+ "@Nullable public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int)",
+ "@Nullable public android.view.ActionMode startActionMode(android.view.ActionMode.Callback)",
+ "@Nullable public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int)",
+
+ // Uses android.view.MenuItem
+ "public boolean onContextItemSelected(@NonNull android.view.MenuItem)",
+ "public void onContextMenuClosed(@NonNull android.view.Menu)",
+ "public boolean onMenuItemSelected(int, @NonNull android.view.MenuItem)",
+ "public boolean onOptionsItemSelected(@NonNull android.view.MenuItem)",
+
+ // Uses android.view.ContextMenu
+ "public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo)",
+
+ // Uses android.app.Dialog
+ "@Deprecated protected android.app.Dialog onCreateDialog(int)",
+ "@Deprecated @Nullable protected android.app.Dialog onCreateDialog(int, android.os.Bundle)",
+ "@Deprecated protected void onPrepareDialog(int, android.app.Dialog)",
+ "@Deprecated protected void onPrepareDialog(int, android.app.Dialog, android.os.Bundle)",
+
+ // Uses android.app.TaskStackBuilder
+ "public void onCreateNavigateUpTaskStack(android.app.TaskStackBuilder)",
+ "public void onPrepareNavigateUpTaskStack(android.app.TaskStackBuilder)",
+
+ // Uses android.view.Menu
+ "public boolean onCreateOptionsMenu(android.view.Menu)",
+ "public boolean onCreatePanelMenu(int, @NonNull android.view.Menu)",
+ "public boolean onMenuOpened(int, @NonNull android.view.Menu)",
+ "public void onOptionsMenuClosed(android.view.Menu)",
+ "public void onPanelClosed(int, @NonNull android.view.Menu)",
+ "public boolean onPrepareOptionsMenu(android.view.Menu)",
+
+ // Uses android.graphics.Canvas
+ "@Deprecated public boolean onCreateThumbnail(android.graphics.Bitmap, android.graphics.Canvas)",
+
+ // Uses android.os.CancellationSignal
+ "public void onGetDirectActions(@NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<java.util.List<android.app.DirectAction>>)",
+ "public void onPerformDirectAction(@NonNull String, @NonNull android.os.Bundle, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.os.Bundle>)",
+
+ // Uses android.view.SearchEvent
+ "public boolean onSearchRequested(@Nullable android.view.SearchEvent)",
+
+ // Uses android.app.Application.ActivityLifecycleCallbacks
+ "public void registerActivityLifecycleCallbacks(@NonNull android.app.Application.ActivityLifecycleCallbacks)",
+ "public void unregisterActivityLifecycleCallbacks(@NonNull android.app.Application.ActivityLifecycleCallbacks)",
+
+ // Uses Runnable
+ "public final void runOnUiThread(Runnable)",
+
+ // Uses android.widget.Toolbar
+ "public void setActionBar(@Nullable android.widget.Toolbar)",
+
+ // Uses android.app.SharedElementCallback
+ "public void setEnterSharedElementCallback(android.app.SharedElementCallback)",
+ "public void setExitSharedElementCallback(android.app.SharedElementCallback)",
+
+ // Uses Drawable
+ "public final void setFeatureDrawable(int, android.graphics.drawable.Drawable)",
+
+ // Uses android.media.session.MediaController
+ "public final void setMediaController(android.media.session.MediaController)",
+
+ // Context
+
+ // Uses Object
+ "public abstract Object getSystemService(@NonNull String)",
+
+ // ContextThemeWrapper
+ "protected void onApplyThemeResource(android.content.res.Resources.Theme, int, boolean)"
);
@@ -325,7 +490,7 @@
m, processingEnv.getTypeUtils(), processingEnv.getElementUtils()))
.collect(Collectors.toSet());
- for (String systemService : SYSTEM_SERVICES) {
+ for (String systemService : FRAMEWORK_CLASSES) {
TypeElement typeElement =
processingEnv.getElementUtils().getTypeElement(systemService);
generateRemoteSystemService(
@@ -551,7 +716,7 @@
TypeSpec.classBuilder(
className)
.addSuperinterface(interfaceClassName)
- .addModifiers(Modifier.FINAL, Modifier.PUBLIC);
+ .addModifiers(Modifier.PUBLIC);
classBuilder.addField(ClassName.get(frameworkClass),
"mFrameworkClass", Modifier.PRIVATE, Modifier.FINAL);
@@ -616,9 +781,22 @@
private Set<ExecutableElement> filterMethods(
Set<ExecutableElement> allMethods, Apis validApis, Elements elements) {
- return allMethods.stream()
- .filter(m -> validApis.methods().contains(MethodSignature.forMethod(m, elements)))
- .collect(Collectors.toSet());
+ Set<ExecutableElement> filteredMethods = new HashSet<>();
+
+ for (ExecutableElement method : allMethods) {
+ MethodSignature methodSignature = MethodSignature.forMethod(method, elements);
+ if (validApis.methods().contains(methodSignature)) {
+ if (method.getModifiers().contains(Modifier.PROTECTED)) {
+ System.out.println(methodSignature + " is protected. Dropping");
+ } else {
+ filteredMethods.add(method);
+ }
+ } else {
+ System.out.println("No matching public API for " + methodSignature);
+ }
+ }
+
+ return filteredMethods;
}
private void writeClassToFile(String packageName, TypeSpec clazz) {
diff --git a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/apis/current.txt b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/apis/current.txt
index 7d544eb..adabda3 100644
--- a/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/apis/current.txt
+++ b/common/device-side/bedstead/remoteframeworkclasses/src/processor/res/apis/current.txt
@@ -3918,7 +3918,6 @@
method public void dump(@NonNull String, @Nullable java.io.FileDescriptor, @NonNull java.io.PrintWriter, @Nullable String[]);
method @Deprecated public void enterPictureInPictureMode();
method public boolean enterPictureInPictureMode(@NonNull android.app.PictureInPictureParams);
- method public <T extends android.view.View> T findViewById(@IdRes int);
method public void finish();
method public void finishActivity(int);
method @Deprecated public void finishActivityFromChild(@NonNull android.app.Activity, int);
@@ -4082,7 +4081,6 @@
method public final void requestShowKeyboardShortcuts();
method @Deprecated public boolean requestVisibleBehind(boolean);
method public final boolean requestWindowFeature(int);
- method @NonNull public final <T extends android.view.View> T requireViewById(@IdRes int);
method public final void runOnUiThread(Runnable);
method public void setActionBar(@Nullable android.widget.Toolbar);
method public void setContentTransitionManager(android.transition.TransitionManager);
@@ -10535,7 +10533,6 @@
method @NonNull public final String getString(@StringRes int);
method @NonNull public final String getString(@StringRes int, java.lang.Object...);
method public abstract Object getSystemService(@NonNull String);
- method public final <T> T getSystemService(@NonNull Class<T>);
method @Nullable public abstract String getSystemServiceName(@NonNull Class<?>);
method @NonNull public final CharSequence getText(@StringRes int);
method public abstract android.content.res.Resources.Theme getTheme();
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivity.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivity.java
index 2636ffd..fb020a2 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivity.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivity.java
@@ -17,11 +17,9 @@
package com.android.bedstead.testapp;
import android.app.Activity;
-import android.content.ComponentName;
import android.os.UserHandle;
import com.android.bedstead.nene.activities.NeneActivity;
-import com.android.bedstead.nene.activities.NeneActivityDirect;
import com.android.bedstead.nene.packages.ComponentReference;
/**
@@ -38,11 +36,6 @@
}
@Override
- public ComponentName getComponentName() {
- return component().componentName();
- }
-
- @Override
public UserHandle getUser() {
return testAppInstance().user().userHandle();
}
diff --git a/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java
index 4ff1c6e..87550ab 100644
--- a/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java
+++ b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java
@@ -33,11 +33,13 @@
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@@ -70,10 +72,10 @@
ClassName.get("com.android.bedstead.nene.utils", "Retry");
private static final ClassName CONTEXT_CLASSNAME =
ClassName.get("android.content", "Context");
- private static final ClassName NENE_ACTIVITY_CLASSNAME =
+ private static final ClassName REMOTE_ACTIVITY_CLASSNAME =
ClassName.get(
- "com.android.bedstead.nene.activities",
- "NeneActivityDirect");
+ "android.app",
+ "RemoteActivity");
private static final ClassName TEST_APP_ACTIVITY_CLASSNAME =
ClassName.get(
"com.android.bedstead.testapp",
@@ -105,10 +107,6 @@
private static final ClassName CROSS_PROFILE_CONNECTOR_CLASSNAME =
ClassName.get("com.google.android.enterprise.connectedapps",
"CrossProfileConnector");
- private static final ClassName UNAVAILABLE_PROFILE_EXCEPTION_CLASSNAME =
- ClassName.get(
- "com.google.android.enterprise.connectedapps.exceptions",
- "UnavailableProfileException");
private static final ClassName PROFILE_RUNTIME_EXCEPTION_CLASSNAME =
ClassName.get(
"com.google.android.enterprise.connectedapps.exceptions",
@@ -168,7 +166,7 @@
TypeElement neneActivityInterface =
processingEnv.getElementUtils().getTypeElement(
- NENE_ACTIVITY_CLASSNAME.canonicalName());
+ REMOTE_ACTIVITY_CLASSNAME.canonicalName());
Set<? extends Element> receiverAnnotatedElements =
roundEnv.getElementsAnnotatedWith(TestAppReceiver.class);
@@ -195,8 +193,7 @@
generateDpmParentWrapper(processingEnv.getElementUtils());
for (TypeElement systemServiceClass : systemServiceClasses) {
- generateRemoteFrameworkClassWrapper(
- processingEnv.getElementUtils(), systemServiceClass);
+ generateRemoteFrameworkClassWrapper(systemServiceClass);
}
}
@@ -207,8 +204,7 @@
return true;
}
- private void generateRemoteFrameworkClassWrapper(
- Elements elements, TypeElement systemServiceClass) {
+ private void generateRemoteFrameworkClassWrapper(TypeElement systemServiceClass) {
ClassName originalClassName = ClassName.get(systemServiceClass);
ClassName interfaceClassName = ClassName.get(
originalClassName.packageName(),
@@ -219,7 +215,8 @@
ClassName profileClassName = ClassName.get(
originalClassName.packageName(),
"Profile" + interfaceClassName.simpleName());
- TypeElement interfaceElement = elements.getTypeElement(interfaceClassName.canonicalName());
+ TypeElement interfaceElement =
+ processingEnv.getElementUtils().getTypeElement(interfaceClassName.canonicalName());
TypeSpec.Builder classBuilder =
TypeSpec.classBuilder(
@@ -246,7 +243,8 @@
profileClassName)
.build());
- for (ExecutableElement method : getMethods(interfaceElement)) {
+ for (ExecutableElement method : getMethods(
+ interfaceElement, processingEnv.getElementUtils())) {
MethodSpec.Builder methodBuilder =
MethodSpec.methodBuilder(method.getSimpleName().toString())
.returns(ClassName.get(method.getReturnType()))
@@ -270,7 +268,6 @@
}
-
CodeBlock.Builder logicLambda = CodeBlock.builder()
.add("() -> {\n").indent()
.addStatement("mConnector.connect()");
@@ -361,7 +358,7 @@
.addStatement("mProfileClass = $T.create(connector)", profileClassName)
.build());
- for (ExecutableElement method : getMethods(interfaceElement)) {
+ for (ExecutableElement method : getMethods(interfaceElement, elements)) {
MethodSpec.Builder methodBuilder =
MethodSpec.methodBuilder(method.getSimpleName().toString())
.returns(ClassName.get(method.getReturnType()))
@@ -435,12 +432,16 @@
.addSuperinterface(TARGETED_REMOTE_ACTIVITY_CLASSNAME)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
- for (ExecutableElement method : getMethods(neneActivityInterface)) {
+ for (ExecutableElement method : getMethods(neneActivityInterface,
+ processingEnv.getElementUtils())) {
MethodSpec.Builder methodBuilder =
MethodSpec.methodBuilder(method.getSimpleName().toString())
.returns(ClassName.get(method.getReturnType()))
.addModifiers(Modifier.PUBLIC)
- .addAnnotation(Override.class);
+ .addAnnotation(Override.class)
+ .addExceptions(
+ method.getThrownTypes().stream().map(TypeName::get).collect(
+ Collectors.toSet()));
methodBuilder.addParameter(
ParameterSpec.builder(String.class, "activityClassName").build());
@@ -498,7 +499,8 @@
PROFILE_TARGETED_REMOTE_ACTIVITY_CLASSNAME)
.build());
- for (ExecutableElement method : getMethods(neneActivityInterface)) {
+ for (ExecutableElement method : getMethods(neneActivityInterface,
+ processingEnv.getElementUtils())) {
MethodSpec.Builder methodBuilder =
MethodSpec.methodBuilder(method.getSimpleName().toString())
.returns(ClassName.get(method.getReturnType()))
@@ -589,12 +591,16 @@
.build());
- for (ExecutableElement method : getMethods(neneActivityInterface)) {
+ for (ExecutableElement method : getMethods(neneActivityInterface,
+ processingEnv.getElementUtils())) {
MethodSpec.Builder methodBuilder =
MethodSpec.methodBuilder(method.getSimpleName().toString())
.returns(ClassName.get(method.getReturnType()))
.addModifiers(Modifier.PUBLIC)
- .addAnnotation(Override.class);
+ .addAnnotation(Override.class)
+ .addExceptions(
+ method.getThrownTypes().stream().map(TypeName::get).collect(
+ Collectors.toSet()));
String params = "mActivityClassName";
@@ -628,12 +634,16 @@
TARGETED_REMOTE_ACTIVITY_CLASSNAME)
.addModifiers(Modifier.PUBLIC);
- for (ExecutableElement method : getMethods(neneActivityInterface)) {
+ for (ExecutableElement method : getMethods(neneActivityInterface,
+ processingEnv.getElementUtils())) {
MethodSpec.Builder methodBuilder =
MethodSpec.methodBuilder(method.getSimpleName().toString())
.returns(ClassName.get(method.getReturnType()))
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
- .addAnnotation(CrossProfile.class);
+ .addAnnotation(CrossProfile.class)
+ .addExceptions(
+ method.getThrownTypes().stream().map(TypeName::get).collect(
+ Collectors.toSet()));
methodBuilder.addParameter(
ParameterSpec.builder(String.class, "activityClassName").build());
@@ -741,10 +751,21 @@
}
}
- private Set<ExecutableElement> getMethods(TypeElement interfaceClass) {
- return interfaceClass.getEnclosedElements().stream()
+ private Set<ExecutableElement> getMethods(TypeElement interfaceClass, Elements elements) {
+ Set<ExecutableElement> methods = new HashSet<>();
+ getMethods(methods, interfaceClass, elements);
+ return methods;
+ }
+
+ private void getMethods(Set<ExecutableElement> methods, TypeElement interfaceClass,
+ Elements elements) {
+ methods.addAll(interfaceClass.getEnclosedElements().stream()
.filter(e -> e instanceof ExecutableElement)
.map(e -> (ExecutableElement) e)
- .collect(Collectors.toSet());
+ .collect(Collectors.toSet()));
+
+ interfaceClass.getInterfaces().stream()
+ .map(m -> elements.getTypeElement(m.toString()))
+ .forEach(m -> getMethods(methods, m, elements));
}
}