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));
     }
 }