diff options
192 files changed, 7942 insertions, 898 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 08a09e1b1a73..b1f587e45a6d 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -334,7 +334,7 @@ java_aconfig_library { aconfig_declarations { name: "android.app.flags-aconfig", package: "android.app", - srcs: ["core/java/android/app/activity_manager.aconfig"], + srcs: ["core/java/android/app/*.aconfig"], } java_aconfig_library { diff --git a/core/api/current.txt b/core/api/current.txt index 40ea02d95613..43c8214e9749 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -5952,6 +5952,7 @@ package android.app { public class GrammaticalInflectionManager { method public int getApplicationGrammaticalGender(); + method @FlaggedApi("android.app.system_terms_of_address_enabled") public int getSystemGrammaticalGender(); method public void setRequestedApplicationGrammaticalGender(int); } @@ -6749,7 +6750,6 @@ package android.app { method public android.app.Notification.WearableExtender clone(); method public android.app.Notification.Builder extend(android.app.Notification.Builder); method public java.util.List<android.app.Notification.Action> getActions(); - method @Deprecated public android.graphics.Bitmap getBackground(); method public String getBridgeTag(); method public int getContentAction(); method @Deprecated public int getContentIcon(); @@ -6768,7 +6768,6 @@ package android.app { method @Deprecated public boolean getHintShowBackgroundOnly(); method @Deprecated public java.util.List<android.app.Notification> getPages(); method public boolean getStartScrollBottom(); - method @Deprecated public android.app.Notification.WearableExtender setBackground(android.graphics.Bitmap); method public android.app.Notification.WearableExtender setBridgeTag(String); method public android.app.Notification.WearableExtender setContentAction(int); method @Deprecated public android.app.Notification.WearableExtender setContentIcon(int); diff --git a/core/api/removed.txt b/core/api/removed.txt index 8b3696a1e6d9..57e2e73854c1 100644 --- a/core/api/removed.txt +++ b/core/api/removed.txt @@ -23,6 +23,11 @@ package android.app { method @Deprecated public android.app.Notification.Builder setTimeout(long); } + public static final class Notification.WearableExtender implements android.app.Notification.Extender { + method @Deprecated public android.graphics.Bitmap getBackground(); + method @Deprecated public android.app.Notification.WearableExtender setBackground(android.graphics.Bitmap); + } + } package android.app.slice { diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 25c48e630380..183783bdf309 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -62,7 +62,7 @@ import android.app.servertransaction.ActivityLifecycleItem.LifecycleState; import android.app.servertransaction.ActivityRelaunchItem; import android.app.servertransaction.ActivityResultItem; import android.app.servertransaction.ClientTransaction; -import android.app.servertransaction.ClientTransactionItem; +import android.app.servertransaction.DestroyActivityItem; import android.app.servertransaction.PauseActivityItem; import android.app.servertransaction.PendingTransactionActions; import android.app.servertransaction.PendingTransactionActions.StopInfo; @@ -375,8 +375,8 @@ public final class ActivityThread extends ClientTransactionHandler @GuardedBy("mPendingOverrideConfigs") private final ArrayMap<IBinder, Configuration> mPendingOverrideConfigs = new ArrayMap<>(); /** The activities to be truly destroyed (not include relaunch). */ - final Map<IBinder, ClientTransactionItem> mActivitiesToBeDestroyed = - Collections.synchronizedMap(new ArrayMap<IBinder, ClientTransactionItem>()); + final Map<IBinder, DestroyActivityItem> mActivitiesToBeDestroyed = + Collections.synchronizedMap(new ArrayMap<>()); // List of new activities that should be reported when next we idle. final ArrayList<ActivityClientRecord> mNewActivities = new ArrayList<>(); // Number of activities that are currently visible on-screen. @@ -5799,7 +5799,7 @@ public final class ActivityThread extends ClientTransactionHandler } @Override - public Map<IBinder, ClientTransactionItem> getActivitiesToBeDestroyed() { + public Map<IBinder, DestroyActivityItem> getActivitiesToBeDestroyed() { return mActivitiesToBeDestroyed; } diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java index 98020ff2d173..25075e91088f 100644 --- a/core/java/android/app/ClientTransactionHandler.java +++ b/core/java/android/app/ClientTransactionHandler.java @@ -19,7 +19,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityThread.ActivityClientRecord; import android.app.servertransaction.ClientTransaction; -import android.app.servertransaction.ClientTransactionItem; +import android.app.servertransaction.DestroyActivityItem; import android.app.servertransaction.PendingTransactionActions; import android.app.servertransaction.TransactionExecutor; import android.content.Context; @@ -108,7 +108,7 @@ public abstract class ClientTransactionHandler { // and deliver callbacks. /** Get activity and its corresponding transaction item which are going to destroy. */ - public abstract Map<IBinder, ClientTransactionItem> getActivitiesToBeDestroyed(); + public abstract Map<IBinder, DestroyActivityItem> getActivitiesToBeDestroyed(); /** Destroy the activity. */ public abstract void handleDestroyActivity(@NonNull ActivityClientRecord r, boolean finishing, diff --git a/core/java/android/app/GrammaticalInflectionManager.java b/core/java/android/app/GrammaticalInflectionManager.java index 1905b6a46d7e..bc6fe6146764 100644 --- a/core/java/android/app/GrammaticalInflectionManager.java +++ b/core/java/android/app/GrammaticalInflectionManager.java @@ -16,12 +16,15 @@ package android.app; +import android.annotation.FlaggedApi; +import android.annotation.NonNull; import android.annotation.SystemService; import android.content.Context; import android.content.res.Configuration; import android.os.RemoteException; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -31,11 +34,15 @@ import java.util.Set; */ @SystemService(Context.GRAMMATICAL_INFLECTION_SERVICE) public class GrammaticalInflectionManager { - private static final Set<Integer> VALID_GENDER_VALUES = new HashSet<>(Arrays.asList( + + /** @hide */ + @NonNull + public static final Set<Integer> VALID_GRAMMATICAL_GENDER_VALUES = + Collections.unmodifiableSet(new HashSet<>(Arrays.asList( Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED, Configuration.GRAMMATICAL_GENDER_NEUTRAL, Configuration.GRAMMATICAL_GENDER_FEMININE, - Configuration.GRAMMATICAL_GENDER_MASCULINE)); + Configuration.GRAMMATICAL_GENDER_MASCULINE))); private final Context mContext; private final IGrammaticalInflectionManager mService; @@ -79,7 +86,7 @@ public class GrammaticalInflectionManager { */ public void setRequestedApplicationGrammaticalGender( @Configuration.GrammaticalGender int grammaticalGender) { - if (!VALID_GENDER_VALUES.contains(grammaticalGender)) { + if (!VALID_GRAMMATICAL_GENDER_VALUES.contains(grammaticalGender)) { throw new IllegalArgumentException("Unknown grammatical gender"); } @@ -90,4 +97,44 @@ public class GrammaticalInflectionManager { throw e.rethrowFromSystemServer(); } } + + /** + * Sets the current grammatical gender for all privileged applications. The value will be + * stored in an encrypted file at {@link android.os.Environment#getDataSystemCeDirectory(int) + * + * @param grammaticalGender the terms of address the user preferred in system. + * + * @see Configuration#getGrammaticalGender + * @hide + */ + public void setSystemWideGrammaticalGender( + @Configuration.GrammaticalGender int grammaticalGender) { + if (!VALID_GRAMMATICAL_GENDER_VALUES.contains(grammaticalGender)) { + throw new IllegalArgumentException("Unknown grammatical gender"); + } + + try { + mService.setSystemWideGrammaticalGender(mContext.getUserId(), grammaticalGender); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Get the current grammatical gender of privileged application from the encrypted file, + * which is stored under {@link android.os.Environment#getDataSystemCeDirectory(int)}. + * + * @return the value of grammatical gender + * + * @see Configuration#getGrammaticalGender + */ + @FlaggedApi(Flags.FLAG_SYSTEM_TERMS_OF_ADDRESS_ENABLED) + @Configuration.GrammaticalGender + public int getSystemGrammaticalGender() { + try { + return mService.getSystemGrammaticalGender(mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/app/IGrammaticalInflectionManager.aidl b/core/java/android/app/IGrammaticalInflectionManager.aidl index 9366a45551da..48a48416d592 100644 --- a/core/java/android/app/IGrammaticalInflectionManager.aidl +++ b/core/java/android/app/IGrammaticalInflectionManager.aidl @@ -16,4 +16,14 @@ package android.app; * Sets a specified app’s app-specific grammatical gender. */ void setRequestedApplicationGrammaticalGender(String appPackageName, int userId, int gender); - }
\ No newline at end of file + + /** + * Sets the grammatical gender to system. + */ + void setSystemWideGrammaticalGender(int userId, int gender); + + /** + * Gets the grammatical gender from system. + */ + int getSystemGrammaticalGender(int userId); + } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 2c42df3c8819..93c2b5ad4d86 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -44,6 +44,9 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.admin.DevicePolicyManager; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; @@ -296,6 +299,15 @@ public class Notification implements Parcelable public static final String EXTRA_REMOTE_INPUT_DRAFT = "android.remoteInputDraft"; /** + * The call to WearableExtender#setBackground(Bitmap) will have no effect and the passed + * Bitmap will not be retained in memory. + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) + @VisibleForTesting + static final long WEARABLE_EXTENDER_BACKGROUND_BLOCKED = 270551184L; + + /** * A timestamp related to this notification, in milliseconds since the epoch. * * Default value: {@link System#currentTimeMillis() Now}. @@ -11148,9 +11160,20 @@ public class Notification implements Parcelable wearableBundle.putParcelableArray(KEY_PAGES, mPages.toArray( new Notification[mPages.size()])); } + if (mBackground != null) { - wearableBundle.putParcelable(KEY_BACKGROUND, mBackground); + // Keeping WearableExtender backgrounds in memory despite them being deprecated has + // added noticeable increase in system server and system ui memory usage. After + // target VERSION_CODE#VANILLA_ICE_CREAM the background will not be populated + // anymore. + if (CompatChanges.isChangeEnabled(WEARABLE_EXTENDER_BACKGROUND_BLOCKED)) { + Log.d(TAG, "Use of background in WearableExtenders has been deprecated and " + + "will not be populated anymore."); + } else { + wearableBundle.putParcelable(KEY_BACKGROUND, mBackground); + } } + if (mContentIcon != 0) { wearableBundle.putInt(KEY_CONTENT_ICON, mContentIcon); } @@ -11369,12 +11392,21 @@ public class Notification implements Parcelable * * @param background the background bitmap * @return this object for method chaining - * @see android.app.Notification.WearableExtender#getBackground - * @deprecated Background images are no longer supported. + * @removed Not functional since {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}. + * The wearable background is not used by wearables anymore and uses up + * unnecessary memory. */ @Deprecated public WearableExtender setBackground(Bitmap background) { - mBackground = background; + // Keeping WearableExtender backgrounds in memory despite them being deprecated has + // added noticeable increase in system server and system ui memory usage. After + // target VERSION_CODE#VANILLA_ICE_CREAM the background will not be populated anymore. + if (CompatChanges.isChangeEnabled(WEARABLE_EXTENDER_BACKGROUND_BLOCKED)) { + Log.d(TAG, "Use of background in WearableExtenders has been deprecated and " + + "will not be populated anymore."); + } else { + mBackground = background; + } return this; } @@ -11384,11 +11416,13 @@ public class Notification implements Parcelable * will work with any notification style. * * @return the background image - * @see android.app.Notification.WearableExtender#setBackground - * @deprecated Background images are no longer supported. + * @removed Not functional since {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}. The + * wearable background is not used by wearables anymore and uses up + * unnecessary memory. */ @Deprecated public Bitmap getBackground() { + Log.w(TAG, "Use of background in WearableExtender has been removed, returning null."); return mBackground; } diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS index e1c45d98e678..9cf54e3b9063 100644 --- a/core/java/android/app/OWNERS +++ b/core/java/android/app/OWNERS @@ -54,6 +54,9 @@ per-file IBackupAgent.aidl = file:/services/backup/OWNERS per-file Broadcast* = file:/BROADCASTS_OWNERS per-file ReceiverInfo* = file:/BROADCASTS_OWNERS +# GrammaticalInflectionManager +per-file *GrammaticalInflection* = file:/services/core/java/com/android/server/grammaticalinflection/OWNERS + # KeyguardManager per-file KeyguardManager.java = file:/services/core/java/com/android/server/locksettings/OWNERS diff --git a/core/java/android/app/grammatical_inflection_manager.aconfig b/core/java/android/app/grammatical_inflection_manager.aconfig new file mode 100644 index 000000000000..989ce61337a3 --- /dev/null +++ b/core/java/android/app/grammatical_inflection_manager.aconfig @@ -0,0 +1,8 @@ +package: "android.app" + +flag { + name: "system_terms_of_address_enabled" + namespace: "grammatical_gender" + description: "Feature flag for System Terms of Address" + bug: "297798866" +} diff --git a/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java index a5b0f18dad3b..8617386516af 100644 --- a/core/java/android/app/servertransaction/ClientTransaction.java +++ b/core/java/android/app/servertransaction/ClientTransaction.java @@ -23,7 +23,6 @@ import android.annotation.Nullable; import android.app.ClientTransactionHandler; import android.app.IApplicationThread; import android.compat.annotation.UnsupportedAppUsage; -import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; @@ -83,23 +82,6 @@ public class ClientTransaction implements Parcelable, ObjectPoolItem { return mActivityCallbacks; } - /** Get the target activity. */ - @Nullable - @UnsupportedAppUsage - public IBinder getActivityToken() { - // TODO(b/260873529): remove after we allow multiple activity items in one transaction. - if (mLifecycleStateRequest != null) { - return mLifecycleStateRequest.getActivityToken(); - } - for (int i = mActivityCallbacks.size() - 1; i >= 0; i--) { - final IBinder token = mActivityCallbacks.get(i).getActivityToken(); - if (token != null) { - return token; - } - } - return null; - } - /** Get the target state lifecycle request. */ @VisibleForTesting(visibility = PACKAGE) @UnsupportedAppUsage diff --git a/core/java/android/app/servertransaction/DestroyActivityItem.java b/core/java/android/app/servertransaction/DestroyActivityItem.java index ddb6df10517c..f9cf075d6062 100644 --- a/core/java/android/app/servertransaction/DestroyActivityItem.java +++ b/core/java/android/app/servertransaction/DestroyActivityItem.java @@ -50,6 +50,13 @@ public class DestroyActivityItem extends ActivityLifecycleItem { } @Override + public void postExecute(@NonNull ClientTransactionHandler client, + @NonNull PendingTransactionActions pendingActions) { + // Cleanup after execution. + client.getActivitiesToBeDestroyed().remove(getActivityToken()); + } + + @Override public int getTargetState() { return ON_DESTROY; } diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java index 44336735254d..066f9fe84970 100644 --- a/core/java/android/app/servertransaction/TransactionExecutor.java +++ b/core/java/android/app/servertransaction/TransactionExecutor.java @@ -47,7 +47,6 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import java.util.List; -import java.util.Map; /** * Class that manages transaction execution in the correct order. @@ -75,34 +74,14 @@ public class TransactionExecutor { * either remain in the initial state, or last state needed by a callback. */ public void execute(@NonNull ClientTransaction transaction) { - if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Start resolving transaction"); - - final IBinder token = transaction.getActivityToken(); - if (token != null) { - final Map<IBinder, ClientTransactionItem> activitiesToBeDestroyed = - mTransactionHandler.getActivitiesToBeDestroyed(); - final ClientTransactionItem destroyItem = activitiesToBeDestroyed.get(token); - if (destroyItem != null) { - if (transaction.getLifecycleStateRequest() == destroyItem) { - // It is going to execute the transaction that will destroy activity with the - // token, so the corresponding to-be-destroyed record can be removed. - activitiesToBeDestroyed.remove(token); - } - if (mTransactionHandler.getActivityClient(token) == null) { - // The activity has not been created but has been requested to destroy, so all - // transactions for the token are just like being cancelled. - Slog.w(TAG, tId(transaction) + "Skip pre-destroyed transaction:\n" - + transactionToString(transaction, mTransactionHandler)); - return; - } - } + if (DEBUG_RESOLVER) { + Slog.d(TAG, tId(transaction) + "Start resolving transaction"); + Slog.d(TAG, transactionToString(transaction, mTransactionHandler)); } - if (DEBUG_RESOLVER) Slog.d(TAG, transactionToString(transaction, mTransactionHandler)); - executeCallbacks(transaction); - executeLifecycleState(transaction); + mPendingActions.clear(); if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "End resolving transaction"); } @@ -135,6 +114,14 @@ public class TransactionExecutor { final IBinder token = item.getActivityToken(); ActivityClientRecord r = mTransactionHandler.getActivityClient(token); + if (token != null && r == null + && mTransactionHandler.getActivitiesToBeDestroyed().containsKey(token)) { + // The activity has not been created but has been requested to destroy, so all + // transactions for the token are just like being cancelled. + Slog.w(TAG, "Skip pre-destroyed transaction item:\n" + item); + continue; + } + if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callback: " + item); final int postExecutionState = item.getPostExecutionState(); @@ -211,6 +198,10 @@ public class TransactionExecutor { } if (r == null) { + if (mTransactionHandler.getActivitiesToBeDestroyed().get(token) == lifecycleItem) { + // Always cleanup for destroy item. + lifecycleItem.postExecute(mTransactionHandler, mPendingActions); + } // Ignore requests for non-existent client records for now. return; } diff --git a/core/java/android/hardware/radio/ProgramSelector.java b/core/java/android/hardware/radio/ProgramSelector.java index 727716e67f28..12442ba12044 100644 --- a/core/java/android/hardware/radio/ProgramSelector.java +++ b/core/java/android/hardware/radio/ProgramSelector.java @@ -147,8 +147,8 @@ public final class ProgramSelector implements Parcelable { * * <p>Consists of (from the LSB): * <li> - * <ul>132bit: Station ID number. - * <ul>14bit: HD_SUBCHANNEL. + * <ul>32bit: Station ID number. + * <ul>4bit: HD_SUBCHANNEL. * <ul>18bit: AMFM_FREQUENCY. * </li> * diff --git a/core/java/android/net/metrics/WakeupEvent.java b/core/java/android/net/metrics/WakeupEvent.java index af9a73ca31ee..53a3ea516530 100644 --- a/core/java/android/net/metrics/WakeupEvent.java +++ b/core/java/android/net/metrics/WakeupEvent.java @@ -29,7 +29,7 @@ public class WakeupEvent { public String iface; public int uid; public int ethertype; - public MacAddress dstHwAddr; + public MacAddress dstHwAddr; // actually used to store a src mac address public String srcIp; public String dstIp; public int ipNextHeader; @@ -44,7 +44,7 @@ public class WakeupEvent { j.add(iface); j.add("uid: " + Integer.toString(uid)); j.add("eth=0x" + Integer.toHexString(ethertype)); - j.add("dstHw=" + dstHwAddr); + j.add("srcMac=" + dstHwAddr); // really!! http://b/292404319#comment11 if (ipNextHeader > 0) { j.add("ipNxtHdr=" + ipNextHeader); j.add("srcIp=" + srcIp); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 80b7d40c14c5..4c8ef97a7437 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -2940,6 +2940,12 @@ public class UserManager { * Used to check if the context user is a restricted profile. Restricted profiles * may have a reduced number of available apps, app restrictions, and account restrictions. * + * <p>The caller must be in the same profile group as the context user or else hold + * <li>{@link android.Manifest.permission#MANAGE_USERS}, + * <li>or {@link android.Manifest.permission#CREATE_USERS}, + * <li>or, for devices after {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, + * {@link android.Manifest.permission#QUERY_USERS}. + * * @return whether the context user is a restricted profile. * @hide */ @@ -2963,6 +2969,12 @@ public class UserManager { * Check if a user is a restricted profile. Restricted profiles may have a reduced number of * available apps, app restrictions, and account restrictions. * + * <p>Requires + * <li>{@link android.Manifest.permission#MANAGE_USERS}, + * <li>or {@link android.Manifest.permission#CREATE_USERS}, + * <li>or, for devices after {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, + * {@link android.Manifest.permission#QUERY_USERS}. + * * @param user the user to check * @return whether the user is a restricted profile. * @hide diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig index 77be5d400853..1294f983b3b9 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -6,3 +6,10 @@ flag { description: "enable device aware permission APIs" bug: "274852670" } + +flag { + name: "voice_activation_permission_apis" + namespace: "permissions" + description: "enable voice activation permission APIs" + bug: "287264308" +}
\ No newline at end of file diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index e829ca288925..f40232b266d0 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9908,6 +9908,48 @@ public final class Settings { */ public static final String DOCK_SETUP_STATE = "dock_setup_state"; + + /** + * Default, indicates that the user has not yet started the hub mode tutorial. + * + * @hide + */ + public static final int HUB_MODE_TUTORIAL_NOT_STARTED = 0; + + /** + * Indicates that the user has started but not yet completed the hub mode tutorial. + * One of the possible states for {@link #HUB_MODE_TUTORIAL_STATE}. + * + * @hide + */ + public static final int HUB_MODE_TUTORIAL_STARTED = 1; + + /** + * Indicates that the user has completed the hub mode tutorial. + * One of the possible states for {@link #HUB_MODE_TUTORIAL_STATE}. + * + * @hide + */ + public static final int HUB_MODE_TUTORIAL_COMPLETED = 10; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + HUB_MODE_TUTORIAL_NOT_STARTED, + HUB_MODE_TUTORIAL_STARTED, + HUB_MODE_TUTORIAL_COMPLETED + }) + public @interface HubModeTutorialState { + } + + /** + * Defines the user's current state of navigating through the hub mode tutorial. + * The possible states are defined in {@link HubModeTutorialState}. + * + * @hide + */ + public static final String HUB_MODE_TUTORIAL_STATE = "hub_mode_tutorial_state"; + /** * The default NFC payment component * @hide @@ -11105,6 +11147,12 @@ public final class Settings { public static final String BLUETOOTH_ON_WHILE_DRIVING = "bluetooth_on_while_driving"; /** + * Volume dialog timeout in ms. + * @hide + */ + public static final String VOLUME_DIALOG_DISMISS_TIMEOUT = "volume_dialog_dismiss_timeout"; + + /** * What behavior should be invoked when the volume hush gesture is triggered * One of VOLUME_HUSH_OFF, VOLUME_HUSH_VIBRATE, VOLUME_HUSH_MUTE. * diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index 969b6a5125d0..e4e8b7b5b6a1 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -54,9 +54,9 @@ import android.view.flags.Flags; * <th style="text-align: center;">SurfaceView</th> * </tr> * <tr> - * <td>Supports alpha</td> + * <td>Supports View alpha</td> * <td style="text-align: center;">X</td> - * <td style="text-align: center;"> </td> + * <td style="text-align: center;">U+</td> * </tr> * <tr> * <td>Supports rotations</td> diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 55374b994cd4..5eaded218a0b 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -8562,6 +8562,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * announcements every time a View is updated. * * <p> + * For notifying users about errors, such as in a login screen with text that displays an + * "incorrect password" notification, that view should send an AccessibilityEvent of type + * {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_ERROR} and set + * {@link AccessibilityNodeInfo#setError(CharSequence)} instead. Custom widgets should expose + * error-setting methods that support accessibility automatically. For example, instead of + * explicitly sending this event when using a TextView, use + * {@link android.widget.TextView#setError(CharSequence)}. + * + * <p> * Use {@link #setStateDescription(CharSequence)} to convey state changes to views within the * user interface. While a live region may send different types of events generated by the view, * state description will send {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events of diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java index a88e394c0985..451acbe84a60 100644 --- a/core/java/android/window/StartingWindowInfo.java +++ b/core/java/android/window/StartingWindowInfo.java @@ -122,7 +122,7 @@ public final class StartingWindowInfo implements Parcelable { TYPE_PARAMETER_PROCESS_RUNNING, TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT, TYPE_PARAMETER_ACTIVITY_CREATED, - TYPE_PARAMETER_ALLOW_ICON, + TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN, TYPE_PARAMETER_ALLOW_HANDLE_SOLID_COLOR_SCREEN, TYPE_PARAMETER_WINDOWLESS, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN @@ -143,7 +143,7 @@ public final class StartingWindowInfo implements Parcelable { /** @hide */ public static final int TYPE_PARAMETER_ACTIVITY_CREATED = 0x00000010; /** @hide */ - public static final int TYPE_PARAMETER_ALLOW_ICON = 0x00000020; + public static final int TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN = 0x00000020; /** * The parameter which indicates if the activity has finished drawing. * @hide diff --git a/core/java/com/android/internal/display/BrightnessSynchronizer.java b/core/java/com/android/internal/display/BrightnessSynchronizer.java index 7a87c3a82e43..d503904c2e3c 100644 --- a/core/java/com/android/internal/display/BrightnessSynchronizer.java +++ b/core/java/com/android/internal/display/BrightnessSynchronizer.java @@ -16,11 +16,9 @@ package com.android.internal.display; -import android.annotation.SuppressLint; import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; -import android.hardware.display.BrightnessInfo; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.net.Uri; @@ -56,7 +54,8 @@ public class BrightnessSynchronizer { private static final int MSG_RUN_UPDATE = 1; // The tolerance within which we consider brightness values approximately equal to eachother. - public static final float EPSILON = 0.0001f; + // This value is approximately 1/3 of the smallest possible brightness value. + public static final float EPSILON = 0.001f; private static int sBrightnessUpdateCount = 1; @@ -285,74 +284,6 @@ public class BrightnessSynchronizer { } /** - * Converts between the int brightness setting and the float brightness system. The int - * brightness setting is between 0-255 and matches the brightness slider - e.g. 128 is 50% on - * the slider. Accounts for special values such as OFF and invalid values. Accounts for - * brightness limits; the maximum value here represents the max value allowed on the slider. - */ - @VisibleForTesting - @SuppressLint("AndroidFrameworkRequiresPermission") - public float brightnessIntSettingToFloat(int brightnessInt) { - if (brightnessInt == PowerManager.BRIGHTNESS_OFF) { - return PowerManager.BRIGHTNESS_OFF_FLOAT; - } else if (brightnessInt == PowerManager.BRIGHTNESS_INVALID) { - return PowerManager.BRIGHTNESS_INVALID_FLOAT; - } else { - final float minInt = PowerManager.BRIGHTNESS_OFF + 1; - final float maxInt = PowerManager.BRIGHTNESS_ON; - - // Normalize to the range [0, 1] - float userPerceptionBrightness = MathUtils.norm(minInt, maxInt, brightnessInt); - - // Convert from user-perception to linear scale - float linearBrightness = BrightnessUtils.convertGammaToLinear(userPerceptionBrightness); - - // Interpolate to the range [0, currentlyAllowedMax] - final Display display = mContext.getDisplay(); - if (display == null) { - return PowerManager.BRIGHTNESS_INVALID_FLOAT; - } - final BrightnessInfo info = display.getBrightnessInfo(); - return MathUtils.lerp(info.brightnessMinimum, info.brightnessMaximum, linearBrightness); - } - } - - /** - * Translates specified value from the float brightness system to the setting int brightness - * system. The value returned is between 0-255 and matches the brightness slider - e.g. 128 is - * 50% on the slider. Accounts for special values such as OFF and invalid values. Accounts for - * brightness limits; the maximum value here represents the max value currently allowed on - * the slider. - */ - @VisibleForTesting - @SuppressLint("AndroidFrameworkRequiresPermission") - public int brightnessFloatToIntSetting(float brightnessFloat) { - if (floatEquals(brightnessFloat, PowerManager.BRIGHTNESS_OFF_FLOAT)) { - return PowerManager.BRIGHTNESS_OFF; - } else if (Float.isNaN(brightnessFloat)) { - return PowerManager.BRIGHTNESS_INVALID; - } else { - // Normalize to the range [0, 1] - final Display display = mContext.getDisplay(); - if (display == null) { - return PowerManager.BRIGHTNESS_INVALID; - } - final BrightnessInfo info = display.getBrightnessInfo(); - float linearBrightness = - MathUtils.norm(info.brightnessMinimum, info.brightnessMaximum, brightnessFloat); - - // Convert from linear to user-perception scale - float userPerceptionBrightness = BrightnessUtils.convertLinearToGamma(linearBrightness); - - // Interpolate to the range [0, 255] - final float minInt = PowerManager.BRIGHTNESS_OFF + 1; - final float maxInt = PowerManager.BRIGHTNESS_ON; - float intBrightness = MathUtils.lerp(minInt, maxInt, userPerceptionBrightness); - return Math.round(intBrightness); - } - } - - /** * Encapsulates a brightness change event and contains logic for synchronizing the appropriate * settings for the specified brightness change. */ @@ -490,14 +421,14 @@ public class BrightnessSynchronizer { if (mSourceType == TYPE_INT) { return (int) mBrightness; } - return brightnessFloatToIntSetting(mBrightness); + return brightnessFloatToInt(mBrightness); } private float getBrightnessAsFloat() { if (mSourceType == TYPE_FLOAT) { return mBrightness; } - return brightnessIntSettingToFloat((int) mBrightness); + return brightnessIntToFloat((int) mBrightness); } private String toStringLabel(int type, float brightness) { diff --git a/core/java/com/android/internal/net/OWNERS b/core/java/com/android/internal/net/OWNERS index 71f997bb57c5..71576837c2e1 100644 --- a/core/java/com/android/internal/net/OWNERS +++ b/core/java/com/android/internal/net/OWNERS @@ -1,4 +1,4 @@ set noparent -file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking +file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking jsharkey@android.com diff --git a/core/java/com/android/server/net/OWNERS b/core/java/com/android/server/net/OWNERS index 62c5737a2e8e..c24680e9b06a 100644 --- a/core/java/com/android/server/net/OWNERS +++ b/core/java/com/android/server/net/OWNERS @@ -1,2 +1,2 @@ set noparent -file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking +file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index c00a776fc3da..4e073ca3863e 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4830,7 +4830,7 @@ <string translatable="false" name="config_deviceSpecificInputMethodManagerService"></string> <!-- Component name of media projection permission dialog --> - <string name="config_mediaProjectionPermissionDialogComponent" translatable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string> + <string name="config_mediaProjectionPermissionDialogComponent" translatable="false">com.android.systemui/com.android.systemui.mediaprojection.permission.MediaProjectionPermissionActivity</string> <!-- Corner radius of system dialogs --> <dimen name="config_dialogCornerRadius">28dp</dimen> diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java index 48dc167438da..7f3e01432dd9 100644 --- a/core/tests/coretests/src/android/app/NotificationTest.java +++ b/core/tests/coretests/src/android/app/NotificationTest.java @@ -69,6 +69,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.annotation.Nullable; +import android.compat.testing.PlatformCompatChangeRule; import android.content.Context; import android.content.Intent; import android.content.LocusId; @@ -95,16 +96,20 @@ import android.util.Pair; import android.widget.RemoteViews; import androidx.test.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.internal.R; import com.android.internal.util.ContrastColorUtil; import junit.framework.Assert; +import libcore.junit.util.compat.CoreCompatChangeRule; + import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TestRule; import org.junit.runner.RunWith; import java.util.List; @@ -116,6 +121,9 @@ public class NotificationTest { private Context mContext; + @Rule + public TestRule compatChangeRule = new PlatformCompatChangeRule(); + @Before public void setUp() { mContext = InstrumentationRegistry.getContext(); @@ -1777,6 +1785,42 @@ public class NotificationTest { assertThat(recoveredExtender.getColor()).isEqualTo(1234); } + @Test + @CoreCompatChangeRule.EnableCompatChanges({Notification.WEARABLE_EXTENDER_BACKGROUND_BLOCKED}) + public void wearableBackgroundBlockEnabled_wearableBackgroundSet_valueRemainsNull() { + Notification.WearableExtender extender = new Notification.WearableExtender(); + Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888); + extender.setBackground(bitmap); + Notification notif = + new Notification.Builder(mContext, "test id") + .setSmallIcon(1) + .setContentTitle("test_title") + .extend(extender) + .build(); + + Notification.WearableExtender result = new Notification.WearableExtender(notif); + Assert.assertNull(result.getBackground()); + } + + @Test + @CoreCompatChangeRule.DisableCompatChanges({Notification.WEARABLE_EXTENDER_BACKGROUND_BLOCKED}) + public void wearableBackgroundBlockDisabled_wearableBackgroundSet_valueKeepsBitmap() { + Notification.WearableExtender extender = new Notification.WearableExtender(); + Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888); + extender.setBackground(bitmap); + Notification notif = + new Notification.Builder(mContext, "test id") + .setSmallIcon(1) + .setContentTitle("test_title") + .extend(extender) + .build(); + + Notification.WearableExtender result = new Notification.WearableExtender(notif); + Bitmap resultBitmap = result.getBackground(); + assertNotNull(resultBitmap); + Assert.assertEquals(bitmap, resultBitmap); + } + private void assertValid(Notification.Colors c) { // Assert that all colors are populated assertThat(c.getBackgroundColor()).isNotEqualTo(Notification.COLOR_INVALID); diff --git a/core/tests/coretests/src/android/app/servertransaction/DestroyActivityItemTest.java b/core/tests/coretests/src/android/app/servertransaction/DestroyActivityItemTest.java new file mode 100644 index 000000000000..ecd75a8370ce --- /dev/null +++ b/core/tests/coretests/src/android/app/servertransaction/DestroyActivityItemTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.servertransaction; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import android.app.ActivityThread.ActivityClientRecord; +import android.app.ClientTransactionHandler; +import android.os.IBinder; +import android.platform.test.annotations.Presubmit; +import android.util.ArrayMap; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Tests for {@link DestroyActivityItem}. + * + * Build/Install/Run: + * atest FrameworksCoreTests:DestroyActivityItemTest + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +@Presubmit +public class DestroyActivityItemTest { + + @Mock + private ClientTransactionHandler mHandler; + @Mock + private PendingTransactionActions mPendingActions; + @Mock + private IBinder mActivityToken; + + // Can't mock final class. + private ActivityClientRecord mActivityClientRecord; + + private ArrayMap<IBinder, DestroyActivityItem> mActivitiesToBeDestroyed; + private DestroyActivityItem mItem; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mItem = DestroyActivityItem.obtain( + mActivityToken, false /* finished */, 123 /* configChanges */); + mActivityClientRecord = new ActivityClientRecord(); + mActivitiesToBeDestroyed = new ArrayMap<>(); + + doReturn(mActivitiesToBeDestroyed).when(mHandler).getActivitiesToBeDestroyed(); + } + + @Test + public void testPreExecute() { + mItem.preExecute(mHandler); + + assertEquals(1, mActivitiesToBeDestroyed.size()); + assertEquals(mItem, mActivitiesToBeDestroyed.get(mActivityToken)); + } + + @Test + public void testPostExecute() { + mItem.preExecute(mHandler); + mItem.postExecute(mHandler, mPendingActions); + + assertTrue(mActivitiesToBeDestroyed.isEmpty()); + } + + @Test + public void testExecute() { + mItem.execute(mHandler, mActivityClientRecord, mPendingActions); + + verify(mHandler).handleDestroyActivity(eq(mActivityClientRecord), eq(false) /* finishing */, + eq(123) /* configChanges */, eq(false) /* getNonConfigInstance */, any()); + } +} diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java index a1a2bdbe0f15..44a4d580dbc0 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java @@ -28,6 +28,7 @@ import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.inOrder; @@ -247,7 +248,7 @@ public class TransactionExecutorTests { @Test public void testDoNotLaunchDestroyedActivity() { - final Map<IBinder, ClientTransactionItem> activitiesToBeDestroyed = new ArrayMap<>(); + final Map<IBinder, DestroyActivityItem> activitiesToBeDestroyed = new ArrayMap<>(); when(mTransactionHandler.getActivitiesToBeDestroyed()).thenReturn(activitiesToBeDestroyed); // Assume launch transaction is still in queue, so there is no client record. when(mTransactionHandler.getActivityClient(any())).thenReturn(null); @@ -259,7 +260,7 @@ public class TransactionExecutorTests { DestroyActivityItem.obtain(token, false /* finished */, 0 /* configChanges */)); destroyTransaction.preExecute(mTransactionHandler); // The activity should be added to to-be-destroyed container. - assertEquals(1, mTransactionHandler.getActivitiesToBeDestroyed().size()); + assertEquals(1, activitiesToBeDestroyed.size()); // A previous queued launch transaction runs on main thread (execute). final ClientTransaction launchTransaction = ClientTransaction.obtain(null /* client */); @@ -274,7 +275,7 @@ public class TransactionExecutorTests { // After the destroy transaction has been executed, the token should be removed. mExecutor.execute(destroyTransaction); - assertEquals(0, mTransactionHandler.getActivitiesToBeDestroyed().size()); + assertTrue(activitiesToBeDestroyed.isEmpty()); } @Test diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java index 6ea6516a96f5..72fc8686f648 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java @@ -30,7 +30,7 @@ import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCR import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK; import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING; import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH; -import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_ICON; +import static android.window.StartingWindowInfo.TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN; import static android.window.StartingWindowInfo.TYPE_PARAMETER_WINDOWLESS; import android.window.StartingWindowInfo; @@ -52,7 +52,8 @@ public class PhoneStartingWindowTypeAlgorithm implements StartingWindowTypeAlgor final boolean processRunning = (parameter & TYPE_PARAMETER_PROCESS_RUNNING) != 0; final boolean allowTaskSnapshot = (parameter & TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT) != 0; final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0; - final boolean allowIcon = (parameter & TYPE_PARAMETER_ALLOW_ICON) != 0; + final boolean isSolidColorSplashScreen = + (parameter & TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN) != 0; final boolean legacySplashScreen = ((parameter & TYPE_PARAMETER_LEGACY_SPLASH_SCREEN) != 0); final boolean activityDrawn = (parameter & TYPE_PARAMETER_ACTIVITY_DRAWN) != 0; @@ -66,13 +67,13 @@ public class PhoneStartingWindowTypeAlgorithm implements StartingWindowTypeAlgor + "processRunning=%b, " + "allowTaskSnapshot=%b, " + "activityCreated=%b, " - + "allowIcon=%b, " + + "isSolidColorSplashScreen=%b, " + "legacySplashScreen=%b, " + "activityDrawn=%b, " + "windowless=%b, " + "topIsHome=%b", newTask, taskSwitch, processRunning, allowTaskSnapshot, activityCreated, - allowIcon, legacySplashScreen, activityDrawn, windowlessSurface, + isSolidColorSplashScreen, legacySplashScreen, activityDrawn, windowlessSurface, topIsHome); if (windowlessSurface) { @@ -80,7 +81,7 @@ public class PhoneStartingWindowTypeAlgorithm implements StartingWindowTypeAlgor } if (!topIsHome) { if (!processRunning || newTask || (taskSwitch && !activityCreated)) { - return getSplashscreenType(allowIcon, legacySplashScreen); + return getSplashscreenType(isSolidColorSplashScreen, legacySplashScreen); } } @@ -94,18 +95,18 @@ public class PhoneStartingWindowTypeAlgorithm implements StartingWindowTypeAlgor } } if (!activityDrawn && !topIsHome) { - return getSplashscreenType(allowIcon, legacySplashScreen); + return getSplashscreenType(isSolidColorSplashScreen, legacySplashScreen); } } return STARTING_WINDOW_TYPE_NONE; } - private static int getSplashscreenType(boolean allowIcon, boolean legacySplashScreen) { - if (allowIcon) { - return legacySplashScreen ? STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN + private static int getSplashscreenType(boolean solidColorSplashScreen, + boolean legacySplashScreen) { + return solidColorSplashScreen + ? STARTING_WINDOW_TYPE_SOLID_COLOR_SPLASH_SCREEN + : legacySplashScreen + ? STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN : STARTING_WINDOW_TYPE_SPLASH_SCREEN; - } else { - return STARTING_WINDOW_TYPE_SOLID_COLOR_SPLASH_SCREEN; - } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt index b444bad8322e..b0e847f69cd5 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt @@ -26,7 +26,7 @@ import org.junit.Test open class CopyContentInSplitGesturalNavLandscape : CopyContentInSplit(Rotation.ROTATION_90) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt index e2ab989af027..f847e400bebd 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt @@ -26,7 +26,7 @@ import org.junit.Test open class CopyContentInSplitGesturalNavPortrait : CopyContentInSplit(Rotation.ROTATION_0) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt index 22b81028dd1d..31e52e2f2ae8 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt @@ -27,7 +27,7 @@ import org.junit.Test open class DismissSplitScreenByDividerGesturalNavLandscape : DismissSplitScreenByDivider(Rotation.ROTATION_90) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt index 3fb014f9aac9..0870073c5050 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt @@ -27,7 +27,7 @@ import org.junit.Test open class DismissSplitScreenByDividerGesturalNavPortrait : DismissSplitScreenByDivider(Rotation.ROTATION_0) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt index ea1f9426bb81..1bb6c4596cd7 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt @@ -27,7 +27,7 @@ import org.junit.Test open class DismissSplitScreenByGoHomeGesturalNavLandscape : DismissSplitScreenByGoHome(Rotation.ROTATION_90) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt index 8f23a790081d..bb084d6834b0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt @@ -27,7 +27,7 @@ import org.junit.Test open class DismissSplitScreenByGoHomeGesturalNavPortrait : DismissSplitScreenByGoHome(Rotation.ROTATION_0) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt index b0f39e592744..bc5857f06120 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt @@ -26,7 +26,7 @@ import org.junit.Test open class DragDividerToResizeGesturalNavLandscape : DragDividerToResize(Rotation.ROTATION_90) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt index 6ce874641c6f..e4faa4a9116f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt @@ -26,7 +26,7 @@ import org.junit.Test open class DragDividerToResizeGesturalNavPortrait : DragDividerToResize(Rotation.ROTATION_0) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt index 9f74edf0a79a..7431974951a7 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt @@ -27,7 +27,7 @@ import org.junit.Test open class EnterSplitScreenByDragFromAllAppsGesturalNavLandscape : EnterSplitScreenByDragFromAllApps(Rotation.ROTATION_90) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt index 1e4055e2a50b..c2b060975604 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt @@ -27,7 +27,7 @@ import org.junit.Test open class EnterSplitScreenByDragFromAllAppsGesturalNavPortrait : EnterSplitScreenByDragFromAllApps(Rotation.ROTATION_0) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt index c3b8132f4a50..7d1072dc19c2 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt @@ -27,7 +27,7 @@ import org.junit.Test open class EnterSplitScreenByDragFromNotificationGesturalNavLandscape : EnterSplitScreenByDragFromNotification(Rotation.ROTATION_90) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt index 7756d048efbb..79760d1f23d7 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt @@ -27,7 +27,7 @@ import org.junit.Test open class EnterSplitScreenByDragFromNotificationGesturalNavPortrait : EnterSplitScreenByDragFromNotification(Rotation.ROTATION_0) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt index c72aa5aaeca6..ff3729ab96c0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt @@ -27,7 +27,7 @@ import org.junit.Test open class EnterSplitScreenByDragFromShortcutGesturalNavLandscape : EnterSplitScreenByDragFromShortcut(Rotation.ROTATION_90) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt index cc88f27b9045..ffbcfe43f374 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt @@ -27,7 +27,7 @@ import org.junit.Test open class EnterSplitScreenByDragFromShortcutGesturalNavPortrait : EnterSplitScreenByDragFromShortcut(Rotation.ROTATION_0) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt index 87b38b133357..5e937c093eb7 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt @@ -27,7 +27,7 @@ import org.junit.Test open class EnterSplitScreenByDragFromTaskbarGesturalNavLandscape : EnterSplitScreenByDragFromTaskbar(Rotation.ROTATION_90) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt index ca347ed25f08..89db8a0c7a76 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt @@ -27,7 +27,7 @@ import org.junit.Test open class EnterSplitScreenByDragFromTaskbarGesturalNavPortrait : EnterSplitScreenByDragFromTaskbar(Rotation.ROTATION_0) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt index 65978192e8e1..bf4ee7a9bb84 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt @@ -27,7 +27,7 @@ import org.junit.Test open class EnterSplitScreenFromOverviewGesturalNavLandscape : EnterSplitScreenFromOverview(Rotation.ROTATION_90) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt index 6df31fc9419b..7e96f066c1c1 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt @@ -27,7 +27,7 @@ import org.junit.Test open class EnterSplitScreenFromOverviewGesturalNavPortrait : EnterSplitScreenFromOverview(Rotation.ROTATION_0) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt index 02596c5f6202..a84deac7698b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt @@ -27,7 +27,7 @@ import org.junit.Test open class SwitchAppByDoubleTapDividerGesturalNavLandscape : SwitchAppByDoubleTapDivider(Rotation.ROTATION_90) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt index 9d579f60eaaa..afcc743e650d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt @@ -27,7 +27,7 @@ import org.junit.Test open class SwitchAppByDoubleTapDividerGesturalNavPortrait : SwitchAppByDoubleTapDivider(Rotation.ROTATION_0) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt index da853420a705..2f96f5f99a66 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt @@ -27,7 +27,7 @@ import org.junit.Test open class SwitchBackToSplitFromAnotherAppGesturalNavLandscape : SwitchBackToSplitFromAnotherApp(Rotation.ROTATION_90) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt index 1ae2c9eb8a1a..efbeb769508f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt @@ -27,7 +27,7 @@ import org.junit.Test open class SwitchBackToSplitFromAnotherAppGesturalNavPortrait : SwitchBackToSplitFromAnotherApp(Rotation.ROTATION_0) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt index b1b562577acc..232fccc12b1c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt @@ -27,7 +27,7 @@ import org.junit.Test open class SwitchBackToSplitFromHomeGesturalNavLandscape : SwitchBackToSplitFromHome(Rotation.ROTATION_90) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt index 08c437eda71c..d7f2845553f3 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt @@ -27,7 +27,7 @@ import org.junit.Test open class SwitchBackToSplitFromHomeGesturalNavPortrait : SwitchBackToSplitFromHome(Rotation.ROTATION_0) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt index efbf86d028ee..019c946068dd 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt @@ -27,7 +27,7 @@ import org.junit.Test open class SwitchBackToSplitFromRecentGesturalNavLandscape : SwitchBackToSplitFromRecent(Rotation.ROTATION_90) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt index f7072fae2e7d..567886103c61 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt @@ -27,7 +27,7 @@ import org.junit.Test open class SwitchBackToSplitFromRecentGesturalNavPortrait : SwitchBackToSplitFromRecent(Rotation.ROTATION_0) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt index d80d1120017e..b3c4ea2c7c65 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt @@ -27,7 +27,7 @@ import org.junit.Test open class SwitchBetweenSplitPairsGesturalNavLandscape : SwitchBetweenSplitPairs(Rotation.ROTATION_90) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt index 30ec37a41dde..f88180f40196 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt @@ -27,7 +27,7 @@ import org.junit.Test open class SwitchBetweenSplitPairsGesturalNavPortrait : SwitchBetweenSplitPairs(Rotation.ROTATION_0) { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt index 1e086d2f5a9b..391cb9b7c90c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt @@ -28,7 +28,7 @@ import org.junit.runners.BlockJUnit4ClassRunner @RunWith(BlockJUnit4ClassRunner::class) open class UnlockKeyguardToSplitScreenGesturalNavLandscape : UnlockKeyguardToSplitScreen() { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt index 932f89217277..4af133ddaa21 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt @@ -28,7 +28,7 @@ import org.junit.runners.BlockJUnit4ClassRunner @RunWith(BlockJUnit4ClassRunner::class) open class UnlockKeyguardToSplitScreenGesturalNavPortrait : UnlockKeyguardToSplitScreen() { @get:Rule - val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false) + val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false) @PlatinumTest(focusArea = "sysui") @Presubmit diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index 664fbb22b13b..f2c29f4a623e 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -180,7 +180,8 @@ class DesktopTasksControllerTest : ShellTestCase() { controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition())) - val wct = getLatestWct(type = TRANSIT_OPEN, handlerClass = OneShotRemoteHandler::class.java) + val wct = + getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java) assertThat(wct.hierarchyOps).hasSize(3) // Expect order to be from bottom: home, task1, task2 wct.assertReorderAt(index = 0, homeTask) @@ -198,7 +199,8 @@ class DesktopTasksControllerTest : ShellTestCase() { controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition())) - val wct = getLatestWct(type = TRANSIT_OPEN, handlerClass = OneShotRemoteHandler::class.java) + val wct = + getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java) assertThat(wct.hierarchyOps).hasSize(3) // Expect order to be from bottom: home, task1, task2 wct.assertReorderAt(index = 0, homeTask) @@ -216,7 +218,8 @@ class DesktopTasksControllerTest : ShellTestCase() { controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition())) - val wct = getLatestWct(type = TRANSIT_OPEN, handlerClass = OneShotRemoteHandler::class.java) + val wct = + getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java) assertThat(wct.hierarchyOps).hasSize(3) // Expect order to be from bottom: home, task1, task2 wct.assertReorderAt(index = 0, homeTask) @@ -230,7 +233,8 @@ class DesktopTasksControllerTest : ShellTestCase() { controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition())) - val wct = getLatestWct(type = TRANSIT_OPEN, handlerClass = OneShotRemoteHandler::class.java) + val wct = + getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java) assertThat(wct.hierarchyOps).hasSize(1) wct.assertReorderAt(index = 0, homeTask) } @@ -246,7 +250,8 @@ class DesktopTasksControllerTest : ShellTestCase() { controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition())) - val wct = getLatestWct(type = TRANSIT_OPEN, handlerClass = OneShotRemoteHandler::class.java) + val wct = + getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java) assertThat(wct.hierarchyOps).hasSize(2) // Expect order to be from bottom: home, task wct.assertReorderAt(index = 0, homeTaskDefaultDisplay) diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index b0cdb0554c11..230fb07f9f43 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -1167,7 +1167,10 @@ public final class AudioAttributes implements Parcelable { streamType); if (attributes != null) { mUsage = attributes.mUsage; - mContentType = attributes.mContentType; + // on purpose ignoring the content type: stream types are deprecated for + // playback, making assumptions about the content type is prone to + // interpretation errors for ambiguous types such as STREAM_TTS and STREAM_MUSIC + //mContentType = attributes.mContentType; mFlags = attributes.getAllFlags(); mMuteHapticChannels = attributes.areHapticChannelsMuted(); mIsContentSpatialized = attributes.isContentSpatialized(); @@ -1177,49 +1180,47 @@ public final class AudioAttributes implements Parcelable { mSource = attributes.mSource; } } - if (mContentType == CONTENT_TYPE_UNKNOWN) { - switch (streamType) { - case AudioSystem.STREAM_VOICE_CALL: - mContentType = CONTENT_TYPE_SPEECH; - break; - case AudioSystem.STREAM_SYSTEM_ENFORCED: - mFlags |= FLAG_AUDIBILITY_ENFORCED; - // intended fall through, attributes in common with STREAM_SYSTEM - case AudioSystem.STREAM_SYSTEM: - mContentType = CONTENT_TYPE_SONIFICATION; - break; - case AudioSystem.STREAM_RING: - mContentType = CONTENT_TYPE_SONIFICATION; - break; - case AudioSystem.STREAM_MUSIC: - mContentType = CONTENT_TYPE_MUSIC; - break; - case AudioSystem.STREAM_ALARM: - mContentType = CONTENT_TYPE_SONIFICATION; - break; - case AudioSystem.STREAM_NOTIFICATION: - mContentType = CONTENT_TYPE_SONIFICATION; - break; - case AudioSystem.STREAM_BLUETOOTH_SCO: - mContentType = CONTENT_TYPE_SPEECH; - mFlags |= FLAG_SCO; - break; - case AudioSystem.STREAM_DTMF: - mContentType = CONTENT_TYPE_SONIFICATION; - break; - case AudioSystem.STREAM_TTS: - mContentType = CONTENT_TYPE_SONIFICATION; - mFlags |= FLAG_BEACON; - break; - case AudioSystem.STREAM_ACCESSIBILITY: - mContentType = CONTENT_TYPE_SPEECH; - break; - case AudioSystem.STREAM_ASSISTANT: - mContentType = CONTENT_TYPE_SPEECH; - break; - default: - Log.e(TAG, "Invalid stream type " + streamType + " for AudioAttributes"); - } + switch (streamType) { + case AudioSystem.STREAM_VOICE_CALL: + mContentType = CONTENT_TYPE_SPEECH; + break; + case AudioSystem.STREAM_SYSTEM_ENFORCED: + mFlags |= FLAG_AUDIBILITY_ENFORCED; + // intended fall through, attributes in common with STREAM_SYSTEM + case AudioSystem.STREAM_SYSTEM: + mContentType = CONTENT_TYPE_SONIFICATION; + break; + case AudioSystem.STREAM_RING: + mContentType = CONTENT_TYPE_SONIFICATION; + break; + case AudioSystem.STREAM_ALARM: + mContentType = CONTENT_TYPE_SONIFICATION; + break; + case AudioSystem.STREAM_NOTIFICATION: + mContentType = CONTENT_TYPE_SONIFICATION; + break; + case AudioSystem.STREAM_BLUETOOTH_SCO: + mContentType = CONTENT_TYPE_SPEECH; + mFlags |= FLAG_SCO; + break; + case AudioSystem.STREAM_DTMF: + mContentType = CONTENT_TYPE_SONIFICATION; + break; + case AudioSystem.STREAM_TTS: + mContentType = CONTENT_TYPE_SONIFICATION; + mFlags |= FLAG_BEACON; + break; + case AudioSystem.STREAM_ACCESSIBILITY: + mContentType = CONTENT_TYPE_SPEECH; + break; + case AudioSystem.STREAM_ASSISTANT: + mContentType = CONTENT_TYPE_SPEECH; + break; + case AudioSystem.STREAM_MUSIC: + // leaving as CONTENT_TYPE_UNKNOWN + break; + default: + Log.e(TAG, "Invalid stream type " + streamType + " for AudioAttributes"); } if (mUsage == USAGE_UNKNOWN) { mUsage = usageForStreamType(streamType); diff --git a/packages/SettingsLib/tests/integ/AndroidManifest.xml b/packages/SettingsLib/tests/integ/AndroidManifest.xml index a95da3033eae..32048ca6344c 100644 --- a/packages/SettingsLib/tests/integ/AndroidManifest.xml +++ b/packages/SettingsLib/tests/integ/AndroidManifest.xml @@ -41,7 +41,7 @@ </application> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.settingslib" + android:targetPackage="com.android.settingslib.tests.integ" android:label="Tests for SettingsLib"> </instrumentation> </manifest> diff --git a/packages/SettingsLib/tests/integ/AndroidTest.xml b/packages/SettingsLib/tests/integ/AndroidTest.xml index b5d09475269e..d0aee8822a72 100644 --- a/packages/SettingsLib/tests/integ/AndroidTest.xml +++ b/packages/SettingsLib/tests/integ/AndroidTest.xml @@ -21,7 +21,7 @@ <option name="test-suite-tag" value="apct" /> <option name="test-tag" value="SettingsLibTests" /> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > - <option name="package" value="com.android.settingslib" /> + <option name="package" value="com.android.settingslib.tests.integ" /> <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> <option name="hidden-api-checks" value="false"/> </test> diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 1c335445bf80..f6f75de1f24e 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -143,6 +143,7 @@ public class SecureSettings { Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, Settings.Secure.SCREENSAVER_HOME_CONTROLS_ENABLED, Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION, + Settings.Secure.VOLUME_DIALOG_DISMISS_TIMEOUT, Settings.Secure.VOLUME_HUSH_GESTURE, Settings.Secure.MANUAL_RINGER_TOGGLE_COUNT, Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED, @@ -243,6 +244,7 @@ public class SecureSettings { Settings.Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING, Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED, Settings.Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED, - Settings.Secure.SEARCH_LONG_PRESS_HOME_ENABLED + Settings.Secure.SEARCH_LONG_PRESS_HOME_ENABLED, + Settings.Secure.HUB_MODE_TUTORIAL_STATE }; } diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index 301fd6f87aa8..8d13f01f1d03 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -212,6 +212,7 @@ public class SecureSettingsValidators { VALIDATORS.put(Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.SCREENSAVER_HOME_CONTROLS_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION, BOOLEAN_VALIDATOR); + VALIDATORS.put(Secure.VOLUME_DIALOG_DISMISS_TIMEOUT, NON_NEGATIVE_INTEGER_VALIDATOR); VALIDATORS.put(Secure.VOLUME_HUSH_GESTURE, NON_NEGATIVE_INTEGER_VALIDATOR); VALIDATORS.put( Secure.ENABLED_NOTIFICATION_LISTENERS, @@ -389,5 +390,6 @@ public class SecureSettingsValidators { VALIDATORS.put(Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_EDGE_HAPTIC_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.DND_CONFIGS_MIGRATED, BOOLEAN_VALIDATOR); + VALIDATORS.put(Secure.HUB_MODE_TUTORIAL_STATE, NON_NEGATIVE_INTEGER_VALIDATOR); } } diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index b5b873c8231f..9bfc4be0f30d 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -634,7 +634,7 @@ <!-- started from MediaProjectionManager --> <activity - android:name=".media.MediaProjectionPermissionActivity" + android:name=".mediaprojection.permission.MediaProjectionPermissionActivity" android:exported="true" android:theme="@style/Theme.SystemUI.MediaProjectionAlertDialog" android:finishOnCloseSystemDialogs="true" @@ -643,7 +643,7 @@ android:visibleToInstantApps="true"/> <activity - android:name=".media.MediaProjectionAppSelectorActivity" + android:name=".mediaprojection.appselector.MediaProjectionAppSelectorActivity" android:theme="@style/Theme.SystemUI.MediaProjectionAppSelector" android:finishOnCloseSystemDialogs="true" android:excludeFromRecents="true" diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Element.kt index 0cc259ab7015..a62c9840add1 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Element.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Element.kt @@ -151,7 +151,7 @@ internal fun Modifier.element( element.lastAlpha = alpha } } - .testTag(key.name) + .testTag(key.testTag) } private fun shouldDrawElement( @@ -167,7 +167,8 @@ private fun shouldDrawElement( state.fromScene == state.toScene || !layoutImpl.isTransitionReady(state) || state.fromScene !in element.sceneValues || - state.toScene !in element.sceneValues + state.toScene !in element.sceneValues || + !isSharedElementEnabled(layoutImpl, state, element.key) ) { return true } @@ -191,6 +192,26 @@ private fun shouldDrawElement( } } +private fun isSharedElementEnabled( + layoutImpl: SceneTransitionLayoutImpl, + transition: TransitionState.Transition, + element: ElementKey, +): Boolean { + val spec = layoutImpl.transitions.transitionSpec(transition.fromScene, transition.toScene) + val sharedInFromScene = spec.transformations(element, transition.fromScene).shared + val sharedInToScene = spec.transformations(element, transition.toScene).shared + + // The sharedElement() transformation must either be null or be the same in both scenes. + if (sharedInFromScene != sharedInToScene) { + error( + "Different sharedElement() transformations matched $element (from=$sharedInFromScene " + + "to=$sharedInToScene)" + ) + } + + return sharedInFromScene?.enabled ?: true +} + /** * Chain the [com.android.compose.animation.scene.transformation.ModifierTransformation] applied * throughout the current transition, if any. @@ -213,7 +234,7 @@ private fun Modifier.modifierTransformations( return layoutImpl.transitions .transitionSpec(fromScene, state.toScene) - .transformations(element.key) + .transformations(element.key, scene.key) .modifier .fold(this) { modifier, transformation -> with(transformation) { @@ -407,17 +428,20 @@ private inline fun <T> computeValue( // The element is shared: interpolate between the value in fromScene and the value in toScene. // TODO(b/290184746): Support non linear shared paths as well as a way to make sure that shared // elements follow the finger direction. - if (fromValues != null && toValues != null) { + val isSharedElement = fromValues != null && toValues != null + if (isSharedElement && isSharedElementEnabled(layoutImpl, state, element.key)) { return lerp( - sceneValue(fromValues), - sceneValue(toValues), + sceneValue(fromValues!!), + sceneValue(toValues!!), transitionProgress, ) } val transformation = transformation( - layoutImpl.transitions.transitionSpec(fromScene, toScene).transformations(element.key) + layoutImpl.transitions + .transitionSpec(fromScene, toScene) + .transformations(element.key, scene.key) ) // If there is no transformation explicitly associated to this element value, let's use // the value given by the system (like the current position and size given by the layout @@ -426,12 +450,21 @@ private inline fun <T> computeValue( // Get the transformed value, i.e. the target value at the beginning (for entering elements) or // end (for leaving elements) of the transition. + val sceneValues = + checkNotNull( + when { + isSharedElement && scene.key == fromScene -> fromValues + isSharedElement -> toValues + else -> fromValues ?: toValues + } + ) + val targetValue = transformation.transform( layoutImpl, scene, element, - fromValues ?: toValues!!, + sceneValues, state, idleValue, ) @@ -440,7 +473,7 @@ private inline fun <T> computeValue( val rangeProgress = transformation.range?.progress(transitionProgress) ?: transitionProgress // Interpolate between the value at rest and the value before entering/after leaving. - val isEntering = fromValues == null + val isEntering = scene.key == toScene return if (isEntering) { lerp(targetValue, idleValue, rangeProgress) } else { diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ElementMatcher.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ElementMatcher.kt new file mode 100644 index 000000000000..98dbb67d7c66 --- /dev/null +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ElementMatcher.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.compose.animation.scene + +/** An interface to match one or more elements. */ +interface ElementMatcher { + /** Whether the element with key [key] in scene [scene] matches this matcher. */ + fun matches(key: ElementKey, scene: SceneKey): Boolean +} + +/** + * Returns an [ElementMatcher] that matches elements in [scene] also matching [this] + * [ElementMatcher]. + */ +fun ElementMatcher.inScene(scene: SceneKey): ElementMatcher { + val delegate = this + val matcherScene = scene + return object : ElementMatcher { + override fun matches(key: ElementKey, scene: SceneKey): Boolean { + return scene == matcherScene && delegate.matches(key, scene) + } + } +} diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt index f7ebe2fc6d34..b7acc48e2865 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt @@ -16,6 +16,8 @@ package com.android.compose.animation.scene +import androidx.annotation.VisibleForTesting + /** * A base class to create unique keys, associated to an [identity] that is used to check the * equality of two key instances. @@ -41,6 +43,7 @@ class SceneKey( name: String, identity: Any = Object(), ) : Key(name, identity) { + @VisibleForTesting val testTag: String = "scene:$name" /** The unique [ElementKey] identifying this scene's root element. */ val rootElementKey = ElementKey(name, identity) @@ -61,7 +64,9 @@ class ElementKey( */ val isBackground: Boolean = false, ) : Key(name, identity), ElementMatcher { - override fun matches(key: ElementKey): Boolean { + @VisibleForTesting val testTag: String = "element:$name" + + override fun matches(key: ElementKey, scene: SceneKey): Boolean { return key == this } @@ -73,7 +78,9 @@ class ElementKey( /** Matches any element whose [key identity][ElementKey.identity] matches [predicate]. */ fun withIdentity(predicate: (Any) -> Boolean): ElementMatcher { return object : ElementMatcher { - override fun matches(key: ElementKey): Boolean = predicate(key.identity) + override fun matches(key: ElementKey, scene: SceneKey): Boolean { + return predicate(key.identity) + } } } } diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Scene.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Scene.kt index b44c8efc7ee2..3985233bd197 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Scene.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Scene.kt @@ -25,6 +25,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.layout.onPlaced +import androidx.compose.ui.platform.testTag import androidx.compose.ui.unit.IntSize import androidx.compose.ui.zIndex @@ -45,7 +46,9 @@ internal class Scene( @Composable fun Content(modifier: Modifier = Modifier) { - Box(modifier.zIndex(zIndex).onPlaced { size = it.size }) { scope.content() } + Box(modifier.zIndex(zIndex).onPlaced { size = it.size }.testTag(key.testTag)) { + scope.content() + } } override fun toString(): String { diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitions.kt index f4e39023edfe..75dcb2e44c13 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitions.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitions.kt @@ -16,6 +16,7 @@ package com.android.compose.animation.scene +import androidx.annotation.VisibleForTesting import androidx.compose.animation.core.AnimationSpec import androidx.compose.animation.core.snap import androidx.compose.ui.geometry.Offset @@ -28,6 +29,7 @@ import com.android.compose.animation.scene.transformation.ModifierTransformation import com.android.compose.animation.scene.transformation.PropertyTransformation import com.android.compose.animation.scene.transformation.RangedPropertyTransformation import com.android.compose.animation.scene.transformation.ScaleSize +import com.android.compose.animation.scene.transformation.SharedElementTransformation import com.android.compose.animation.scene.transformation.Transformation import com.android.compose.animation.scene.transformation.Translate import com.android.compose.ui.util.fastForEach @@ -35,11 +37,12 @@ import com.android.compose.ui.util.fastMap /** The transitions configuration of a [SceneTransitionLayout]. */ class SceneTransitions( - private val transitionSpecs: List<TransitionSpec>, + @get:VisibleForTesting val transitionSpecs: List<TransitionSpec>, ) { private val cache = mutableMapOf<SceneKey, MutableMap<SceneKey, TransitionSpec>>() - internal fun transitionSpec(from: SceneKey, to: SceneKey): TransitionSpec { + @VisibleForTesting + fun transitionSpec(from: SceneKey, to: SceneKey): TransitionSpec { return cache.getOrPut(from) { mutableMapOf() }.getOrPut(to) { findSpec(from, to) } } @@ -97,7 +100,8 @@ data class TransitionSpec( val transformations: List<Transformation>, val spec: AnimationSpec<Float>, ) { - private val cache = mutableMapOf<ElementKey, ElementTransformations>() + // TODO(b/302300957): Make sure this cache does not infinitely grow. + private val cache = mutableMapOf<ElementKey, MutableMap<SceneKey, ElementTransformations>>() internal fun reverse(): TransitionSpec { return copy( @@ -107,12 +111,18 @@ data class TransitionSpec( ) } - internal fun transformations(element: ElementKey): ElementTransformations { - return cache.getOrPut(element) { computeTransformations(element) } + internal fun transformations(element: ElementKey, scene: SceneKey): ElementTransformations { + return cache + .getOrPut(element) { mutableMapOf() } + .getOrPut(scene) { computeTransformations(element, scene) } } /** Filter [transformations] to compute the [ElementTransformations] of [element]. */ - private fun computeTransformations(element: ElementKey): ElementTransformations { + private fun computeTransformations( + element: ElementKey, + scene: SceneKey, + ): ElementTransformations { + var shared: SharedElementTransformation? = null val modifier = mutableListOf<ModifierTransformation>() var offset: PropertyTransformation<Offset>? = null var size: PropertyTransformation<IntSize>? = null @@ -126,16 +136,16 @@ data class TransitionSpec( is Translate, is EdgeTranslate, is AnchoredTranslate -> { - throwIfNotNull(offset, element, property = "offset") + throwIfNotNull(offset, element, name = "offset") offset = root as PropertyTransformation<Offset> } is ScaleSize, is AnchoredSize -> { - throwIfNotNull(size, element, property = "size") + throwIfNotNull(size, element, name = "size") size = root as PropertyTransformation<IntSize> } is Fade -> { - throwIfNotNull(alpha, element, property = "alpha") + throwIfNotNull(alpha, element, name = "alpha") alpha = root as PropertyTransformation<Float> } is RangedPropertyTransformation -> onPropertyTransformation(root, current.delegate) @@ -143,32 +153,37 @@ data class TransitionSpec( } transformations.fastForEach { transformation -> - if (!transformation.matcher.matches(element)) { + if (!transformation.matcher.matches(element, scene)) { return@fastForEach } when (transformation) { + is SharedElementTransformation -> { + throwIfNotNull(shared, element, name = "shared") + shared = transformation + } is ModifierTransformation -> modifier.add(transformation) is PropertyTransformation<*> -> onPropertyTransformation(transformation) } } - return ElementTransformations(modifier, offset, size, alpha) + return ElementTransformations(shared, modifier, offset, size, alpha) } private fun throwIfNotNull( - previous: PropertyTransformation<*>?, + previous: Transformation?, element: ElementKey, - property: String, + name: String, ) { if (previous != null) { - error("$element has multiple transformations for its $property property") + error("$element has multiple $name transformations") } } } /** The transformations of an element during a transition. */ internal class ElementTransformations( + val shared: SharedElementTransformation?, val modifier: List<ModifierTransformation>, val offset: PropertyTransformation<Offset>?, val size: PropertyTransformation<IntSize>?, diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDsl.kt index fb12b90d7d3e..49669775fedd 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDsl.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDsl.kt @@ -116,6 +116,14 @@ interface TransitionBuilder : PropertyTransformationBuilder { ) /** + * Configure the shared transition when [matcher] is shared between two scenes. + * + * @param enabled whether the matched element(s) should actually be shared in this transition. + * Defaults to true. + */ + fun sharedElement(matcher: ElementMatcher, enabled: Boolean = true) + + /** * Punch a hole in the element(s) matching [matcher] that has the same bounds as [bounds] and * using the given [shape]. * @@ -127,6 +135,13 @@ interface TransitionBuilder : PropertyTransformationBuilder { * the result. */ fun punchHole(matcher: ElementMatcher, bounds: ElementKey, shape: Shape = RectangleShape) + + /** + * Adds the transformations in [builder] but in reversed order. This allows you to partially + * reuse the definition of the transition from scene `Foo` to scene `Bar` inside the definition + * of the transition from scene `Bar` to scene `Foo`. + */ + fun reversed(builder: TransitionBuilder.() -> Unit) } @TransitionDsl @@ -179,12 +194,6 @@ interface PropertyTransformationBuilder { fun anchoredSize(matcher: ElementMatcher, anchor: ElementKey) } -/** An interface to match one or more elements. */ -interface ElementMatcher { - /** Whether the element with key [key] matches this matcher. */ - fun matches(key: ElementKey): Boolean -} - /** The edge of a [SceneTransitionLayout]. */ enum class Edge { Left, diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDslImpl.kt index 48d5638e8b4e..f1c27178391c 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDslImpl.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDslImpl.kt @@ -31,6 +31,7 @@ import com.android.compose.animation.scene.transformation.PropertyTransformation import com.android.compose.animation.scene.transformation.PunchHole import com.android.compose.animation.scene.transformation.RangedPropertyTransformation import com.android.compose.animation.scene.transformation.ScaleSize +import com.android.compose.animation.scene.transformation.SharedElementTransformation import com.android.compose.animation.scene.transformation.Transformation import com.android.compose.animation.scene.transformation.TransformationRange import com.android.compose.animation.scene.transformation.Translate @@ -80,6 +81,7 @@ internal class TransitionBuilderImpl : TransitionBuilder { override var spec: AnimationSpec<Float> = spring(stiffness = Spring.StiffnessLow) private var range: TransformationRange? = null + private var reversed = false private val durationMillis: Int by lazy { val spec = spec if (spec !is DurationBasedAnimationSpec) { @@ -93,6 +95,12 @@ internal class TransitionBuilderImpl : TransitionBuilder { transformations.add(PunchHole(matcher, bounds, shape)) } + override fun reversed(builder: TransitionBuilder.() -> Unit) { + reversed = true + builder() + reversed = false + } + override fun fractionRange( start: Float?, end: Float?, @@ -103,6 +111,10 @@ internal class TransitionBuilderImpl : TransitionBuilder { range = null } + override fun sharedElement(matcher: ElementMatcher, enabled: Boolean) { + transformations.add(SharedElementTransformation(matcher, enabled)) + } + override fun timestampRange( startMillis: Int?, endMillis: Int?, @@ -122,11 +134,20 @@ internal class TransitionBuilderImpl : TransitionBuilder { } private fun transformation(transformation: PropertyTransformation<*>) { - if (range != null) { - transformations.add(RangedPropertyTransformation(transformation, range!!)) - } else { - transformations.add(transformation) - } + val transformation = + if (range != null) { + RangedPropertyTransformation(transformation, range!!) + } else { + transformation + } + + transformations.add( + if (reversed) { + transformation.reverse() + } else { + transformation + } + ) } override fun fade(matcher: ElementMatcher) { diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Transformation.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Transformation.kt index ce6749da2711..a65025423aee 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Transformation.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Transformation.kt @@ -30,6 +30,14 @@ sealed interface Transformation { */ val matcher: ElementMatcher + /** + * The range during which the transformation is applied. If it is `null`, then the + * transformation will be applied throughout the whole scene transition. + */ + // TODO(b/240432457): Move this back to PropertyTransformation. + val range: TransformationRange? + get() = null + /* * Reverse this transformation. This is called when we use Transition(from = A, to = B) when * animating from B to A and there is no Transition(from = B, to = A) defined. @@ -37,6 +45,11 @@ sealed interface Transformation { fun reverse(): Transformation = this } +internal class SharedElementTransformation( + override val matcher: ElementMatcher, + internal val enabled: Boolean, +) : Transformation + /** A transformation that is applied on the element during the whole transition. */ internal interface ModifierTransformation : Transformation { /** Apply the transformation to [element]. */ @@ -53,13 +66,6 @@ internal interface ModifierTransformation : Transformation { /** A transformation that changes the value of an element property, like its size or offset. */ internal sealed interface PropertyTransformation<T> : Transformation { /** - * The range during which the transformation is applied. If it is `null`, then the - * transformation will be applied throughout the whole scene transition. - */ - val range: TransformationRange? - get() = null - - /** * Transform [value], i.e. the value of the transformed property without this transformation. */ // TODO(b/290184746): Figure out a public API for custom transformations that don't have access @@ -92,8 +98,7 @@ internal class RangedPropertyTransformation<T>( } /** The progress-based range of a [PropertyTransformation]. */ -data class TransformationRange -private constructor( +data class TransformationRange( val start: Float, val end: Float, ) { @@ -133,6 +138,6 @@ private constructor( } companion object { - private const val BoundUnspecified = Float.MIN_VALUE + const val BoundUnspecified = Float.MIN_VALUE } } diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt index 8bd654585f29..328866ea76ca 100644 --- a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt +++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt @@ -224,7 +224,7 @@ class SceneTransitionLayoutTest { // In scene A, the shared element SharedFoo() is at the top end of the layout and has a size // of 50.dp. - var sharedFoo = rule.onNodeWithTag(TestElements.Foo.name, useUnmergedTree = true) + var sharedFoo = rule.onNodeWithTag(TestElements.Foo.testTag, useUnmergedTree = true) sharedFoo.assertWidthIsEqualTo(50.dp) sharedFoo.assertHeightIsEqualTo(50.dp) sharedFoo.assertPositionInRootIsEqualTo( @@ -250,7 +250,7 @@ class SceneTransitionLayoutTest { // We need to use onAllNodesWithTag().onFirst() here given that shared elements are // composed and laid out in both scenes (but drawn only in one). - sharedFoo = rule.onAllNodesWithTag(TestElements.Foo.name).onFirst() + sharedFoo = rule.onAllNodesWithTag(TestElements.Foo.testTag).onFirst() // In scene B, foo is at the top start (x = 0, y = 0) of the layout and has a size of // 100.dp. We pause at the middle of the transition, so it should now be 75.dp given that we @@ -284,7 +284,7 @@ class SceneTransitionLayoutTest { val expectedLeft = 0.dp val expectedSize = 100.dp + (150.dp - 100.dp) * interpolatedProgress - sharedFoo = rule.onAllNodesWithTag(TestElements.Foo.name).onFirst() + sharedFoo = rule.onAllNodesWithTag(TestElements.Foo.testTag).onFirst() assertThat((layoutState.transitionState as TransitionState.Transition).progress) .isEqualTo(interpolatedProgress) sharedFoo.assertWidthIsEqualTo(expectedSize) diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TestTransition.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TestTransition.kt index 275149a05abf..268057fd2f2c 100644 --- a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TestTransition.kt +++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TestTransition.kt @@ -23,7 +23,11 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.test.SemanticsNodeInteraction +import androidx.compose.ui.test.SemanticsNodeInteractionCollection +import androidx.compose.ui.test.hasParent +import androidx.compose.ui.test.hasTestTag import androidx.compose.ui.test.junit4.ComposeContentTestRule +import androidx.compose.ui.test.onAllNodesWithTag import androidx.compose.ui.test.onNodeWithTag @DslMarker annotation class TransitionTestDsl @@ -59,8 +63,21 @@ interface TransitionTestBuilder { @TransitionTestDsl interface TransitionTestAssertionScope { - /** Assert on [element]. */ - fun onElement(element: ElementKey): SemanticsNodeInteraction + /** + * Assert on [element]. + * + * Note that presence/value assertions on the returned [SemanticsNodeInteraction] will fail if 0 + * or more than 1 elements matched [element]. If you need to assert on a shared element that + * will be present multiple times in the layout during transitions, either specify the [scene] + * in which you are matching or use [onSharedElement] instead. + */ + fun onElement(element: ElementKey, scene: SceneKey? = null): SemanticsNodeInteraction + + /** + * Assert on a shared [element]. This will throw if [element] is not shared and present only in + * one scene during a transition. + */ + fun onSharedElement(element: ElementKey): SemanticsNodeInteractionCollection } /** @@ -73,20 +90,22 @@ fun ComposeContentTestRule.testTransition( toSceneContent: @Composable SceneScope.() -> Unit, transition: TransitionBuilder.() -> Unit, layoutModifier: Modifier = Modifier, + fromScene: SceneKey = TestScenes.SceneA, + toScene: SceneKey = TestScenes.SceneB, builder: TransitionTestBuilder.() -> Unit, ) { testTransition( - from = TestScenes.SceneA, - to = TestScenes.SceneB, + from = fromScene, + to = toScene, transitionLayout = { currentScene, onChangeScene -> SceneTransitionLayout( currentScene, onChangeScene, - transitions { from(TestScenes.SceneA, to = TestScenes.SceneB, transition) }, + transitions { from(fromScene, to = toScene, transition) }, layoutModifier.fillMaxSize(), ) { - scene(TestScenes.SceneA, content = fromSceneContent) - scene(TestScenes.SceneB, content = toSceneContent) + scene(fromScene, content = fromSceneContent) + scene(toScene, content = toSceneContent) } }, builder, @@ -111,8 +130,24 @@ fun ComposeContentTestRule.testTransition( val test = transitionTest(builder) val assertionScope = object : TransitionTestAssertionScope { - override fun onElement(element: ElementKey): SemanticsNodeInteraction { - return this@testTransition.onNodeWithTag(element.name) + override fun onElement( + element: ElementKey, + scene: SceneKey? + ): SemanticsNodeInteraction { + return if (scene == null) { + onNodeWithTag(element.testTag) + } else { + onNode(hasTestTag(element.testTag) and hasParent(hasTestTag(scene.testTag))) + } + } + + override fun onSharedElement(element: ElementKey): SemanticsNodeInteractionCollection { + val interaction = onAllNodesWithTag(element.testTag) + val matches = interaction.fetchSemanticsNodes(atLeastOneRootRequired = false).size + if (matches < 2) { + error("Element $element is not shared ($matches matches)") + } + return interaction } } diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt new file mode 100644 index 000000000000..fa94b25028a2 --- /dev/null +++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.compose.animation.scene + +import androidx.compose.animation.core.SpringSpec +import androidx.compose.animation.core.TweenSpec +import androidx.compose.animation.core.tween +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.compose.animation.scene.transformation.Transformation +import com.android.compose.animation.scene.transformation.TransformationRange +import com.google.common.truth.Correspondence +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class TransitionDslTest { + @Test + fun emptyTransitions() { + val transitions = transitions {} + assertThat(transitions.transitionSpecs).isEmpty() + } + + @Test + fun manyTransitions() { + val transitions = transitions { + from(TestScenes.SceneA, to = TestScenes.SceneB) + from(TestScenes.SceneB, to = TestScenes.SceneC) + from(TestScenes.SceneC, to = TestScenes.SceneA) + } + assertThat(transitions.transitionSpecs).hasSize(3) + } + + @Test + fun toFromBuilders() { + val transitions = transitions { + from(TestScenes.SceneA, to = TestScenes.SceneB) + from(TestScenes.SceneB) + to(TestScenes.SceneC) + } + + assertThat(transitions.transitionSpecs) + .comparingElementsUsing( + Correspondence.transforming<TransitionSpec, Pair<SceneKey?, SceneKey?>>( + { it?.from to it?.to }, + "has (from, to) equal to" + ) + ) + .containsExactly( + TestScenes.SceneA to TestScenes.SceneB, + TestScenes.SceneB to null, + null to TestScenes.SceneC, + ) + } + + @Test + fun defaultTransitionSpec() { + val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) } + val transition = transitions.transitionSpecs.single() + assertThat(transition.spec).isInstanceOf(SpringSpec::class.java) + } + + @Test + fun customTransitionSpec() { + val transitions = transitions { + from(TestScenes.SceneA, to = TestScenes.SceneB) { spec = tween(durationMillis = 42) } + } + val transition = transitions.transitionSpecs.single() + assertThat(transition.spec).isInstanceOf(TweenSpec::class.java) + assertThat((transition.spec as TweenSpec).durationMillis).isEqualTo(42) + } + + @Test + fun defaultRange() { + val transitions = transitions { + from(TestScenes.SceneA, to = TestScenes.SceneB) { fade(TestElements.Foo) } + } + + val transition = transitions.transitionSpecs.single() + assertThat(transition.transformations.size).isEqualTo(1) + assertThat(transition.transformations.single().range).isEqualTo(null) + } + + @Test + fun fractionRange() { + val transitions = transitions { + from(TestScenes.SceneA, to = TestScenes.SceneB) { + fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) } + fractionRange(start = 0.2f) { fade(TestElements.Foo) } + fractionRange(end = 0.9f) { fade(TestElements.Foo) } + } + } + + val transition = transitions.transitionSpecs.single() + assertThat(transition.transformations) + .comparingElementsUsing(TRANSFORMATION_RANGE) + .containsExactly( + TransformationRange(start = 0.1f, end = 0.8f), + TransformationRange(start = 0.2f, end = TransformationRange.BoundUnspecified), + TransformationRange(start = TransformationRange.BoundUnspecified, end = 0.9f), + ) + } + + @Test + fun timestampRange() { + val transitions = transitions { + from(TestScenes.SceneA, to = TestScenes.SceneB) { + spec = tween(500) + + timestampRange(startMillis = 100, endMillis = 300) { fade(TestElements.Foo) } + timestampRange(startMillis = 200) { fade(TestElements.Foo) } + timestampRange(endMillis = 400) { fade(TestElements.Foo) } + } + } + + val transition = transitions.transitionSpecs.single() + assertThat(transition.transformations) + .comparingElementsUsing(TRANSFORMATION_RANGE) + .containsExactly( + TransformationRange(start = 100 / 500f, end = 300 / 500f), + TransformationRange(start = 200 / 500f, end = TransformationRange.BoundUnspecified), + TransformationRange(start = TransformationRange.BoundUnspecified, end = 400 / 500f), + ) + } + + @Test + fun reversed() { + val transitions = transitions { + from(TestScenes.SceneA, to = TestScenes.SceneB) { + spec = tween(500) + reversed { + fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) } + timestampRange(startMillis = 100, endMillis = 300) { fade(TestElements.Foo) } + } + } + } + + val transition = transitions.transitionSpecs.single() + assertThat(transition.transformations) + .comparingElementsUsing(TRANSFORMATION_RANGE) + .containsExactly( + TransformationRange(start = 1f - 0.8f, end = 1f - 0.1f), + TransformationRange(start = 1f - 300 / 500f, end = 1f - 100 / 500f), + ) + } + + @Test + fun defaultReversed() { + val transitions = transitions { + from(TestScenes.SceneA, to = TestScenes.SceneB) { + spec = tween(500) + fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) } + timestampRange(startMillis = 100, endMillis = 300) { fade(TestElements.Foo) } + } + } + + // Fetch the transition from B to A, which will automatically reverse the transition from A + // to B we defined. + val transition = + transitions.transitionSpec(from = TestScenes.SceneB, to = TestScenes.SceneA) + assertThat(transition.transformations) + .comparingElementsUsing(TRANSFORMATION_RANGE) + .containsExactly( + TransformationRange(start = 1f - 0.8f, end = 1f - 0.1f), + TransformationRange(start = 1f - 300 / 500f, end = 1f - 100 / 500f), + ) + } + + companion object { + private val TRANSFORMATION_RANGE = + Correspondence.transforming<Transformation, TransformationRange?>( + { it?.range }, + "has range equal to" + ) + } +} diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/transformation/SharedElementTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/transformation/SharedElementTest.kt new file mode 100644 index 000000000000..2af363860272 --- /dev/null +++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/transformation/SharedElementTest.kt @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.compose.animation.scene.transformation + +import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.tween +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.size +import androidx.compose.ui.Modifier +import androidx.compose.ui.test.assertPositionInRootIsEqualTo +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.unit.dp +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.compose.animation.scene.Edge +import com.android.compose.animation.scene.TestElements +import com.android.compose.animation.scene.TestScenes +import com.android.compose.animation.scene.inScene +import com.android.compose.animation.scene.testTransition +import com.android.compose.modifiers.size +import com.android.compose.test.assertSizeIsEqualTo +import com.android.compose.test.onEach +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SharedElementTest { + @get:Rule val rule = createComposeRule() + + @Test + fun testSharedElement() { + rule.testTransition( + fromSceneContent = { + // Foo is at (10, 50) with a size of (20, 80). + Box(Modifier.offset(10.dp, 50.dp).element(TestElements.Foo).size(20.dp, 80.dp)) + }, + toSceneContent = { + // Foo is at (50, 70) with a size of (10, 40). + Box(Modifier.offset(50.dp, 70.dp).element(TestElements.Foo).size(10.dp, 40.dp)) + }, + transition = { + spec = tween(16 * 4, easing = LinearEasing) + // Elements should be shared by default. + } + ) { + before { + onElement(TestElements.Foo).assertPositionInRootIsEqualTo(10.dp, 50.dp) + onElement(TestElements.Foo).assertSizeIsEqualTo(20.dp, 80.dp) + } + at(0) { + onSharedElement(TestElements.Foo).onEach { + assertPositionInRootIsEqualTo(10.dp, 50.dp) + assertSizeIsEqualTo(20.dp, 80.dp) + } + } + at(16) { + onSharedElement(TestElements.Foo).onEach { + assertPositionInRootIsEqualTo(20.dp, 55.dp) + assertSizeIsEqualTo(17.5.dp, 70.dp) + } + } + at(32) { + onSharedElement(TestElements.Foo).onEach { + assertPositionInRootIsEqualTo(30.dp, 60.dp) + assertSizeIsEqualTo(15.dp, 60.dp) + } + } + at(48) { + onSharedElement(TestElements.Foo).onEach { + assertPositionInRootIsEqualTo(40.dp, 65.dp) + assertSizeIsEqualTo(12.5.dp, 50.dp) + } + } + after { + onElement(TestElements.Foo).assertPositionInRootIsEqualTo(50.dp, 70.dp) + onElement(TestElements.Foo).assertSizeIsEqualTo(10.dp, 40.dp) + } + } + } + + @Test + fun testSharedElementDisabled() { + rule.testTransition( + fromScene = TestScenes.SceneA, + toScene = TestScenes.SceneB, + // The full layout is 100x100. + layoutModifier = Modifier.size(100.dp), + fromSceneContent = { + Box(Modifier.fillMaxSize()) { + // Foo is at (10, 50). + Box(Modifier.offset(10.dp, 50.dp).element(TestElements.Foo)) + } + }, + toSceneContent = { + Box(Modifier.fillMaxSize()) { + // Foo is at (50, 60). + Box(Modifier.offset(50.dp, 60.dp).element(TestElements.Foo)) + } + }, + transition = { + spec = tween(16 * 4, easing = LinearEasing) + + // Disable the shared element animation. + sharedElement(TestElements.Foo, enabled = false) + + // In SceneA, Foo leaves to the left edge. + translate(TestElements.Foo.inScene(TestScenes.SceneA), Edge.Left) + + // In SceneB, Foo comes from the bottom edge. + translate(TestElements.Foo.inScene(TestScenes.SceneB), Edge.Bottom) + }, + ) { + before { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(10.dp, 50.dp) } + at(0) { + onElement(TestElements.Foo, scene = TestScenes.SceneA) + .assertPositionInRootIsEqualTo(10.dp, 50.dp) + onElement(TestElements.Foo, scene = TestScenes.SceneB) + .assertPositionInRootIsEqualTo(50.dp, 100.dp) + } + at(16) { + onElement(TestElements.Foo, scene = TestScenes.SceneA) + .assertPositionInRootIsEqualTo(7.5.dp, 50.dp) + onElement(TestElements.Foo, scene = TestScenes.SceneB) + .assertPositionInRootIsEqualTo(50.dp, 90.dp) + } + at(32) { + onElement(TestElements.Foo, scene = TestScenes.SceneA) + .assertPositionInRootIsEqualTo(5.dp, 50.dp) + onElement(TestElements.Foo, scene = TestScenes.SceneB) + .assertPositionInRootIsEqualTo(50.dp, 80.dp) + } + at(48) { + onElement(TestElements.Foo, scene = TestScenes.SceneA) + .assertPositionInRootIsEqualTo(2.5.dp, 50.dp) + onElement(TestElements.Foo, scene = TestScenes.SceneB) + .assertPositionInRootIsEqualTo(50.dp, 70.dp) + } + after { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(50.dp, 60.dp) } + } + } +} diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/test/Selectors.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/test/Selectors.kt new file mode 100644 index 000000000000..d6f64bfe4974 --- /dev/null +++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/test/Selectors.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.compose.test + +import androidx.compose.ui.test.SemanticsNodeInteraction +import androidx.compose.ui.test.SemanticsNodeInteractionCollection + +/** Assert [assert] on each element of [this] [SemanticsNodeInteractionCollection]. */ +fun SemanticsNodeInteractionCollection.onEach(assert: SemanticsNodeInteraction.() -> Unit) { + for (i in 0 until this.fetchSemanticsNodes().size) { + get(i).assert() + } +} diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt index c41dc53fdc6b..cb76ad7c77fe 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt @@ -507,9 +507,10 @@ open class ClockRegistry( } } - private var isVerifying = AtomicBoolean(false) + private var isQueued = AtomicBoolean(false) fun verifyLoadedProviders() { - val shouldSchedule = isVerifying.compareAndSet(false, true) + Log.i(TAG, Thread.currentThread().getStackTrace().toString()) + val shouldSchedule = isQueued.compareAndSet(false, true) if (!shouldSchedule) { logger.tryLog( TAG, @@ -521,48 +522,54 @@ open class ClockRegistry( } scope.launch(bgDispatcher) { - if (keepAllLoaded) { - logger.tryLog( - TAG, - LogLevel.INFO, - {}, - { "verifyLoadedProviders: keepAllLoaded=true" } - ) - // Enforce that all plugins are loaded if requested - for ((_, info) in availableClocks) { - info.manager?.loadPlugin() + // TODO(b/267372164): Use better threading approach when converting to flows + synchronized(availableClocks) { + isQueued.set(false) + if (keepAllLoaded) { + logger.tryLog( + TAG, + LogLevel.INFO, + {}, + { "verifyLoadedProviders: keepAllLoaded=true" } + ) + // Enforce that all plugins are loaded if requested + for ((_, info) in availableClocks) { + info.manager?.loadPlugin() + } + return@launch + } + + val currentClock = availableClocks[currentClockId] + if (currentClock == null) { + logger.tryLog( + TAG, + LogLevel.INFO, + {}, + { "verifyLoadedProviders: currentClock=null" } + ) + // Current Clock missing, load no plugins and use default + for ((_, info) in availableClocks) { + info.manager?.unloadPlugin() + } + return@launch } - isVerifying.set(false) - return@launch - } - val currentClock = availableClocks[currentClockId] - if (currentClock == null) { logger.tryLog( TAG, LogLevel.INFO, {}, - { "verifyLoadedProviders: currentClock=null" } + { "verifyLoadedProviders: load currentClock" } ) - // Current Clock missing, load no plugins and use default - for ((_, info) in availableClocks) { - info.manager?.unloadPlugin() - } - isVerifying.set(false) - return@launch - } - - logger.tryLog(TAG, LogLevel.INFO, {}, { "verifyLoadedProviders: load currentClock" }) - val currentManager = currentClock.manager - currentManager?.loadPlugin() + val currentManager = currentClock.manager + currentManager?.loadPlugin() - for ((_, info) in availableClocks) { - val manager = info.manager - if (manager != null && currentManager != manager) { - manager.unloadPlugin() + for ((_, info) in availableClocks) { + val manager = info.manager + if (manager != null && currentManager != manager) { + manager.unloadPlugin() + } } } - isVerifying.set(false) } } diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml index 85fb3ac577bc..587caaf3ecf3 100644 --- a/packages/SystemUI/res/values-land/config.xml +++ b/packages/SystemUI/res/values-land/config.xml @@ -44,6 +44,6 @@ <!-- Whether to force split shade. For now, this value has effect only when flag lockscreen.enable_landscape is enabled. - TODO (b/293290851) - change this comment/resource when flag is enabled --> + TODO (b/293252410) - change this comment/resource when flag is enabled --> <bool name="force_config_use_split_notification_shade">true</bool> </resources> diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml index e63229aea70b..fc6d20e11d3b 100644 --- a/packages/SystemUI/res/values-sw600dp-land/config.xml +++ b/packages/SystemUI/res/values-sw600dp-land/config.xml @@ -38,6 +38,6 @@ <!-- Whether to force split shade. For now, this value has effect only when flag lockscreen.enable_landscape is enabled. - TODO (b/293290851) - change this comment/resource when flag is enabled --> + TODO (b/293252410) - change this comment/resource when flag is enabled --> <bool name="force_config_use_split_notification_shade">false</bool> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index b6bca65b8174..3bdc0af7f7af 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -604,7 +604,7 @@ <!-- Whether to force split shade. For now, this value has effect only when flag lockscreen.enable_landscape is enabled. - TODO (b/293290851) - change this comment/resource when flag is enabled --> + TODO (b/293252410) - change this comment/resource when flag is enabled --> <bool name="force_config_use_split_notification_shade">false</bool> <!-- Whether we use large screen shade header which takes only one row compared to QS header --> diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml index 21696fefb80f..6cdd15e637bd 100644 --- a/packages/SystemUI/res/values/ids.xml +++ b/packages/SystemUI/res/values/ids.xml @@ -233,6 +233,11 @@ <item type="id" name="pin_pad"/> <!-- + Tag used to store pending intent registration listeners in NotificationTemplateViewWrapper + --> + <item type="id" name="pending_intent_listener_tag" /> + + <!-- Used to tag views programmatically added to the smartspace area so they can be more easily removed later. --> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index ba8e42752586..f6a0563ebf94 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -184,6 +184,10 @@ public class KeyguardClockSwitch extends RelativeLayout { } } + public boolean getSplitShadeCentered() { + return mSplitShadeCentered; + } + @Override protected void onFinishInflate() { super.onFinishInflate(); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index 29414ea7f4c0..5646abefcef1 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -234,6 +234,10 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS } } + public KeyguardClockSwitch getView() { + return mView; + } + private void hideSliceViewAndNotificationIconContainer() { View ksv = mView.findViewById(R.id.keyguard_slice_view); ksv.setVisibility(View.GONE); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index d8486029a903..f9cc03eea288 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -18,6 +18,7 @@ package com.android.keyguard; import static java.util.Collections.emptySet; +import android.animation.LayoutTransition; import android.content.Context; import android.graphics.Canvas; import android.os.Build; @@ -78,6 +79,14 @@ public class KeyguardStatusView extends GridLayout { mKeyguardSlice = findViewById(R.id.keyguard_slice_view); mMediaHostContainer = findViewById(R.id.status_view_media_container); + if (mMediaHostContainer != null) { + LayoutTransition mediaLayoutTransition = new LayoutTransition(); + ((ViewGroup) mMediaHostContainer).setLayoutTransition(mediaLayoutTransition); + mediaLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING); + mediaLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING); + mediaLayoutTransition.disableTransitionType(LayoutTransition.APPEARING); + mediaLayoutTransition.disableTransitionType(LayoutTransition.DISAPPEARING); + } updateDark(); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java index 8d0d299e56c2..931ba6d97c58 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java @@ -23,6 +23,7 @@ import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_CL import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; import android.animation.Animator; +import android.animation.LayoutTransition; import android.animation.ValueAnimator; import android.annotation.Nullable; import android.content.res.Configuration; @@ -101,6 +102,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV private final Rect mClipBounds = new Rect(); private final KeyguardInteractor mKeyguardInteractor; + private Boolean mSplitShadeEnabled = false; private Boolean mStatusViewCentered = true; private DumpManager mDumpManager; @@ -150,6 +152,48 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV @Override public void onInit() { mKeyguardClockSwitchController.init(); + final View mediaHostContainer = mView.findViewById(R.id.status_view_media_container); + if (mediaHostContainer != null) { + mKeyguardClockSwitchController.getView().addOnLayoutChangeListener( + (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { + if (!mSplitShadeEnabled + || mKeyguardClockSwitchController.getView().getSplitShadeCentered() + // Note: isKeyguardVisible() returns false after Launcher -> AOD. + || !mKeyguardUpdateMonitor.isKeyguardVisible()) { + return; + } + + int oldHeight = oldBottom - oldTop; + if (v.getHeight() == oldHeight) return; + + if (mediaHostContainer.getVisibility() != View.VISIBLE + // If the media is appearing, also don't do the transition. + || mediaHostContainer.getHeight() == 0) { + return; + } + + final LayoutTransition mediaLayoutTransition = + ((ViewGroup) mediaHostContainer).getLayoutTransition(); + if (mediaLayoutTransition == null) return; + + mediaLayoutTransition.enableTransitionType(LayoutTransition.CHANGING); + }); + + mediaHostContainer.addOnLayoutChangeListener( + (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { + final LayoutTransition mediaLayoutTransition = + ((ViewGroup) mediaHostContainer).getLayoutTransition(); + if (mediaLayoutTransition == null) return; + if (!mediaLayoutTransition.isTransitionTypeEnabled( + LayoutTransition.CHANGING)) { + return; + } + // Note: when this is called, the LayoutTransition is already been set up. + // Disables the LayoutTransition until it's explicitly enabled again. + mediaLayoutTransition.disableTransitionType(LayoutTransition.CHANGING); + } + ); + } mDumpManager.registerDumpable(getInstanceName(), this); if (mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) { @@ -385,6 +429,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV */ public void setSplitShadeEnabled(boolean enabled) { mKeyguardClockSwitchController.setSplitShadeEnabled(enabled); + mSplitShadeEnabled = enabled; } /** diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 165c4bb018d3..a81069a1f7db 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -424,11 +424,11 @@ public class LockIconViewController implements Dumpable { private void updateConfiguration() { WindowManager windowManager = mContext.getSystemService(WindowManager.class); Rect bounds = windowManager.getCurrentWindowMetrics().getBounds(); - WindowInsets insets = windowManager.getCurrentWindowMetrics().getWindowInsets(); mWidthPixels = bounds.right; if (mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE)) { // Assumed to be initially neglected as there are no left or right insets in portrait // However, on landscape, these insets need to included when calculating the midpoint + WindowInsets insets = windowManager.getCurrentWindowMetrics().getWindowInsets(); mWidthPixels -= insets.getSystemWindowInsetLeft() + insets.getSystemWindowInsetRight(); } mHeightPixels = bounds.bottom; diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index 954129ef78c8..22bd20767e14 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -18,8 +18,8 @@ package com.android.systemui; import static androidx.dynamicanimation.animation.DynamicAnimation.TRANSLATION_X; import static androidx.dynamicanimation.animation.FloatPropertyCompat.createFloatPropertyCompat; - import static com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS; +import static com.android.systemui.flags.Flags.SWIPE_UNCLEARED_TRANSIENT_VIEW_FIX; import static com.android.systemui.statusbar.notification.NotificationUtils.logKey; import android.animation.Animator; @@ -482,7 +482,14 @@ public class SwipeHelper implements Gefingerpoken, Dumpable { boolean wasRemoved = false; if (animView instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) animView; - wasRemoved = row.isRemoved(); + if (mFeatureFlags.isEnabled(SWIPE_UNCLEARED_TRANSIENT_VIEW_FIX)) { + // If the view is already removed from its parent and added as Transient, + // we need to clean the transient view upon animation end + wasRemoved = row.getTransientContainer() != null + || row.getParent() == null || row.isRemoved(); + } else { + wasRemoved = row.isRemoved(); + } } if (!mCancelled || wasRemoved) { mCallback.onChildDismissed(animView); diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 3b70555ad32a..871257e6be79 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -303,6 +303,11 @@ object Flags { @JvmField val MIGRATE_CLOCKS_TO_BLUEPRINT = unreleasedFlag("migrate_clocks_to_blueprint") + /** Migrate KeyguardRootView to use composables. */ + // TODO(b/301969856): Tracking Bug. + @JvmField val KEYGUARD_ROOT_VIEW_USE_COMPOSE = + unreleasedFlag("keyguard_root_view_use_compose") + /** Enables preview loading animation in the wallpaper picker. */ // TODO(b/274443705): Tracking Bug @JvmField @@ -771,6 +776,10 @@ object Flags { // TODO(b/302087895): Tracking Bug @JvmField val CALL_LAYOUT_ASYNC_SET_DATA = unreleasedFlag("call_layout_async_set_data") + // TODO(b/302144438): Tracking Bug + @JvmField val DECOUPLE_REMOTE_INPUT_DELEGATE_AND_CALLBACK_UPDATE = + unreleasedFlag("decouple_remote_input_delegate_and_callback_update") + // 2900 - CentralSurfaces-related flags // TODO(b/285174336): Tracking Bug diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt index fb02c7d68a9f..1761ca86f588 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt @@ -26,7 +26,6 @@ import com.android.keyguard.LockIconView import com.android.keyguard.LockIconViewController import com.android.keyguard.dagger.KeyguardStatusViewComponent import com.android.systemui.CoreStartable -import com.android.systemui.res.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags @@ -40,7 +39,9 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel +import com.android.systemui.res.R import com.android.systemui.shade.NotificationShadeWindowView +import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.KeyguardIndicationController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator @@ -69,6 +70,7 @@ constructor( private val context: Context, private val keyguardIndicationController: KeyguardIndicationController, private val lockIconViewController: LockIconViewController, + private val shadeInteractor: ShadeInteractor, ) : CoreStartable { private var rootViewHandle: DisposableHandle? = null @@ -135,6 +137,7 @@ constructor( occludingAppDeviceEntryMessageViewModel, chipbarCoordinator, keyguardStateController, + shadeInteractor ) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt index f564d0073e42..053727ace76d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt @@ -32,6 +32,7 @@ import com.android.systemui.flags.Flags import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.temporarydisplay.ViewPriority @@ -55,6 +56,7 @@ object KeyguardRootViewBinder { occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel, chipbarCoordinator: ChipbarCoordinator, keyguardStateController: KeyguardStateController, + shadeInteractor: ShadeInteractor, ): DisposableHandle { val disposableHandle = view.repeatWhenAttached { @@ -88,6 +90,17 @@ object KeyguardRootViewBinder { } } } + + launch { + shadeInteractor.isAnyFullyExpanded.collect { isFullyAnyExpanded -> + view.visibility = + if (isFullyAnyExpanded) { + View.INVISIBLE + } else { + View.VISIBLE + } + } + } } repeatOnLifecycle(Lifecycle.State.STARTED) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt index 2ad74fbc6674..864e345e9c1e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt @@ -62,6 +62,7 @@ import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessage import com.android.systemui.monet.ColorScheme import com.android.systemui.plugins.ClockController import com.android.systemui.plugins.FalsingManager +import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shared.clocks.ClockRegistry import com.android.systemui.shared.clocks.DefaultClockController import com.android.systemui.shared.clocks.shared.model.ClockPreviewConstants @@ -109,6 +110,7 @@ constructor( private val occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel, private val chipbarCoordinator: ChipbarCoordinator, private val keyguardStateController: KeyguardStateController, + private val shadeInteractor: ShadeInteractor, ) { val hostToken: IBinder? = bundle.getBinder(KEY_HOST_TOKEN) @@ -317,6 +319,7 @@ constructor( occludingAppDeviceEntryMessageViewModel, chipbarCoordinator, keyguardStateController, + shadeInteractor, ) ) rootView.addView( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt index 9409036586e8..f4bc7137b50c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt @@ -29,11 +29,11 @@ import androidx.constraintlayout.widget.ConstraintSet import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.LockIconView import com.android.keyguard.LockIconViewController -import com.android.systemui.res.R import com.android.systemui.biometrics.AuthController import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.keyguard.shared.model.KeyguardSection +import com.android.systemui.res.R import com.android.systemui.shade.NotificationPanelView import javax.inject.Inject @@ -73,11 +73,11 @@ constructor( val mBottomPaddingPx = context.resources.getDimensionPixelSize(R.dimen.lock_icon_margin_bottom) val bounds = windowManager.currentWindowMetrics.bounds - val insets = windowManager.currentWindowMetrics.windowInsets var widthPixels = bounds.right.toFloat() if (featureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE)) { // Assumed to be initially neglected as there are no left or right insets in portrait. // However, on landscape, these insets need to included when calculating the midpoint. + val insets = windowManager.currentWindowMetrics.windowInsets widthPixels -= (insets.systemWindowInsetLeft + insets.systemWindowInsetRight).toFloat() } val heightPixels = bounds.bottom.toFloat() diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionCaptureTarget.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt index fbf9294a0a37..11d0be5fc8bf 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionCaptureTarget.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt @@ -14,20 +14,17 @@ * limitations under the License. */ -package com.android.systemui.media +package com.android.systemui.mediaprojection import android.os.IBinder import android.os.Parcel import android.os.Parcelable /** - * Class that represents an area that should be captured. - * Currently it has only a launch cookie that represents a task but - * we potentially could add more identifiers e.g. for a pair of tasks. + * Class that represents an area that should be captured. Currently it has only a launch cookie that + * represents a task but we potentially could add more identifiers e.g. for a pair of tasks. */ -data class MediaProjectionCaptureTarget( - val launchCookie: IBinder? -): Parcelable { +data class MediaProjectionCaptureTarget(val launchCookie: IBinder?) : Parcelable { constructor(parcel: Parcel) : this(parcel.readStrongBinder()) diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionServiceHelper.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt index 9e616e2355e2..f1cade7512e2 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionServiceHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.media +package com.android.systemui.mediaprojection import android.content.Context import android.media.projection.IMediaProjection diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt index 88bc064c60f7..b5d3e913cadb 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.media +package com.android.systemui.mediaprojection.appselector import android.app.ActivityOptions import android.content.Intent @@ -46,13 +46,11 @@ import com.android.internal.app.chooser.TargetInfo import com.android.internal.widget.RecyclerView import com.android.internal.widget.RecyclerViewAccessibilityDelegate import com.android.internal.widget.ResolverDrawerLayout -import com.android.systemui.res.R -import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorComponent -import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorController -import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorResultHandler -import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorView +import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget +import com.android.systemui.mediaprojection.MediaProjectionServiceHelper import com.android.systemui.mediaprojection.appselector.data.RecentTask import com.android.systemui.mediaprojection.appselector.view.MediaProjectionRecentsViewController +import com.android.systemui.res.R import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.AsyncActivityLauncher import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt index 33d9cc36c9b0..72aea040ba05 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt @@ -23,8 +23,6 @@ import android.os.UserHandle import androidx.lifecycle.DefaultLifecycleObserver import com.android.launcher3.icons.IconFactory import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.media.MediaProjectionAppSelectorActivity -import com.android.systemui.media.MediaProjectionPermissionActivity import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerLabelLoader import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerThumbnailLoader import com.android.systemui.mediaprojection.appselector.data.AppIconLoader @@ -37,6 +35,7 @@ import com.android.systemui.mediaprojection.appselector.view.MediaProjectionRece import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider import com.android.systemui.mediaprojection.devicepolicy.MediaProjectionDevicePolicyModule import com.android.systemui.mediaprojection.devicepolicy.PersonalProfile +import com.android.systemui.mediaprojection.permission.MediaProjectionPermissionActivity import com.android.systemui.statusbar.phone.ConfigurationControllerImpl import com.android.systemui.statusbar.policy.ConfigurationController import dagger.Binds diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseScreenSharePermissionDialog.kt index 64006fe4c265..8b437c322549 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseScreenSharePermissionDialog.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.screenrecord +package com.android.systemui.mediaprojection.permission import android.content.Context import android.os.Bundle diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java index 4de6278400b3..2b56d0cf9f83 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.media; +package com.android.systemui.mediaprojection.permission; import static android.media.projection.IMediaProjectionManager.EXTRA_PACKAGE_REUSING_GRANTED_CONSENT; import static android.media.projection.IMediaProjectionManager.EXTRA_USER_REVIEW_GRANTED_CONSENT; @@ -22,8 +22,8 @@ import static android.media.projection.ReviewGrantedConsentResult.RECORD_CANCEL; import static android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_DISPLAY; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; -import static com.android.systemui.screenrecord.ScreenShareOptionKt.ENTIRE_SCREEN; -import static com.android.systemui.screenrecord.ScreenShareOptionKt.SINGLE_APP; +import static com.android.systemui.mediaprojection.permission.ScreenShareOptionKt.ENTIRE_SCREEN; +import static com.android.systemui.mediaprojection.permission.ScreenShareOptionKt.SINGLE_APP; import android.annotation.Nullable; import android.app.Activity; @@ -51,13 +51,13 @@ import android.text.style.StyleSpan; import android.util.Log; import android.view.Window; -import com.android.systemui.res.R; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.mediaprojection.MediaProjectionServiceHelper; +import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorActivity; import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver; import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDisabledDialog; -import com.android.systemui.screenrecord.MediaProjectionPermissionDialog; -import com.android.systemui.screenrecord.ScreenShareOption; +import com.android.systemui.res.R; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.util.Utils; diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialog.kt index 47e28d86e01d..2f10ad3e6486 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialog.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.screenrecord +package com.android.systemui.mediaprojection.permission import android.content.Context import android.media.projection.MediaProjectionConfig diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenShareOption.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/ScreenShareOption.kt index ebf0dd28fbf4..37e8d9f26ee3 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenShareOption.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/ScreenShareOption.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.screenrecord +package com.android.systemui.mediaprojection.permission import androidx.annotation.IntDef import androidx.annotation.StringRes diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index 9a9626d7c7a0..10f95e0b7201 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -48,6 +48,7 @@ import com.android.systemui.qs.nano.QsTileState; import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedRepository; import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor; import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository; +import com.android.systemui.qs.tiles.di.NewQSTileFactory; import com.android.systemui.settings.UserFileManager; import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.ShadeController; @@ -56,6 +57,8 @@ import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; import com.android.systemui.util.settings.SecureSettings; +import dagger.Lazy; + import org.jetbrains.annotations.NotNull; import java.io.PrintWriter; @@ -121,6 +124,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P @Inject public QSTileHost(Context context, + Lazy<NewQSTileFactory> newQsTileFactoryProvider, QSFactory defaultFactory, @Main Executor mainExecutor, PluginManager pluginManager, @@ -147,6 +151,9 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P mShadeController = shadeController; + if (featureFlags.getPipelineTilesEnabled()) { + mQsFactories.add(newQsTileFactoryProvider.get()); + } mQsFactories.add(defaultFactory); pluginManager.addPluginListener(this, QSFactory.class, true); mUserTracker = userTracker; @@ -326,7 +333,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P try { tile = createTile(tileSpec); if (tile != null) { - tile.setTileSpec(tileSpec); if (tile.isAvailable()) { newTiles.put(tileSpec, tile); mQSLogger.logTileAdded(tileSpec); diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java index a6226b36b0fd..2af7ae0614ac 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java @@ -130,11 +130,9 @@ public class TileQueryHelper { if (tile == null) { continue; } else if (!tile.isAvailable()) { - tile.setTileSpec(spec); tile.destroy(); continue; } - tile.setTileSpec(spec); tilesToAdd.add(tile); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java index 92490e8fbd43..a65967a0349b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java +++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java @@ -31,6 +31,7 @@ import com.android.systemui.qs.ReduceBrightColorsController; import com.android.systemui.qs.external.QSExternalModule; import com.android.systemui.qs.pipeline.dagger.QSPipelineModule; import com.android.systemui.qs.tileimpl.QSTileImpl; +import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.ManagedProfileController; import com.android.systemui.statusbar.policy.CastController; @@ -41,14 +42,14 @@ import com.android.systemui.statusbar.policy.SafetyController; import com.android.systemui.statusbar.policy.WalletController; import com.android.systemui.util.settings.SecureSettings; -import java.util.Map; - -import javax.inject.Named; - import dagger.Module; import dagger.Provides; import dagger.multibindings.Multibinds; +import java.util.Map; + +import javax.inject.Named; + /** * Module for QS dependencies */ @@ -68,6 +69,11 @@ public interface QSModule { @Multibinds Map<String, QSTileImpl<?>> tileMap(); + /** A map of internal QS tile ViewModels. Ensures that this can be injected even if + * it is empty */ + @Multibinds + Map<String, QSTileViewModel> tileViewModelMap(); + @Provides @SysUISingleton static AutoTileManager provideAutoTileManager( diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt index 00c23582f726..c5512c15ccc2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt @@ -41,10 +41,12 @@ import com.android.systemui.qs.pipeline.domain.model.TileModel import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger +import com.android.systemui.qs.tiles.di.NewQSTileFactory import com.android.systemui.qs.toProto import com.android.systemui.settings.UserTracker import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.util.kotlin.pairwise +import dagger.Lazy import java.io.PrintWriter import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher @@ -131,6 +133,7 @@ constructor( private val installedTilesComponentRepository: InstalledTilesComponentRepository, private val userRepository: UserRepository, private val customTileStatePersister: CustomTileStatePersister, + private val newQSTileFactory: Lazy<NewQSTileFactory>, private val tileFactory: QSFactory, private val customTileAddedRepository: CustomTileAddedRepository, private val tileLifecycleManagerFactory: TileLifecycleManager.Factory, @@ -139,7 +142,7 @@ constructor( @Background private val backgroundDispatcher: CoroutineDispatcher, @Application private val scope: CoroutineScope, private val logger: QSPipelineLogger, - featureFlags: QSPipelineFlagsRepository, + private val featureFlags: QSPipelineFlagsRepository, ) : CurrentTilesInteractor { private val _currentSpecsAndTiles: MutableStateFlow<List<TileModel>> = @@ -333,12 +336,19 @@ constructor( } private suspend fun createTile(spec: TileSpec): QSTile? { - val tile = withContext(mainDispatcher) { tileFactory.createTile(spec.spec) } + val tile = + withContext(mainDispatcher) { + if (featureFlags.pipelineTilesEnabled) { + newQSTileFactory.get().createTile(spec.spec) + } else { + null + } + ?: tileFactory.createTile(spec.spec) + } if (tile == null) { logger.logTileNotFoundInFactory(spec) return null } else { - tile.tileSpec = spec.spec return if (!tile.isAvailable) { logger.logTileDestroyed( spec, diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt index 551b0f4890a4..1a71b715fe3a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt @@ -1,7 +1,7 @@ package com.android.systemui.qs.pipeline.shared import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags import javax.inject.Inject @@ -10,7 +10,7 @@ import javax.inject.Inject class QSPipelineFlagsRepository @Inject constructor( - private val featureFlags: FeatureFlags, + private val featureFlags: FeatureFlagsClassic, ) { /** @see Flags.QS_PIPELINE_NEW_HOST */ @@ -20,4 +20,8 @@ constructor( /** @see Flags.QS_PIPELINE_AUTO_ADD */ val pipelineAutoAddEnabled: Boolean get() = pipelineHostEnabled && featureFlags.isEnabled(Flags.QS_PIPELINE_AUTO_ADD) + + /** @see Flags.QS_PIPELINE_NEW_TILES */ + val pipelineTilesEnabled: Boolean + get() = featureFlags.isEnabled(Flags.QS_PIPELINE_NEW_TILES) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt index 11b5dd7cb036..aed08f8b5457 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt @@ -31,11 +31,7 @@ import com.android.systemui.qs.external.CustomTile sealed class TileSpec private constructor(open val spec: String) { /** Represents a spec that couldn't be parsed into a valid type of tile. */ - object Invalid : TileSpec("") { - override fun toString(): String { - return "TileSpec.INVALID" - } - } + data object Invalid : TileSpec("") /** Container for the spec of a tile provided by SystemUI. */ data class PlatformTileSpec diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java index 9c7a73412518..632aa6330a18 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java @@ -70,6 +70,7 @@ public class QSFactoryImpl implements QSFactory { if (tile != null) { tile.initialize(); tile.postStale(); // Tile was just created, must be stale. + tile.setTileSpec(tileSpec); } return tile; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandler.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandler.kt index e9f907c4d8e7..dc9e11567676 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandler.kt @@ -1,11 +1,11 @@ package com.android.systemui.qs.tiles.base.actions import android.content.Intent +import android.view.View import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.dagger.SysUISingleton import com.android.systemui.plugins.ActivityStarter -import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction import javax.inject.Inject /** @@ -17,9 +17,9 @@ class QSTileIntentUserActionHandler @Inject constructor(private val activityStarter: ActivityStarter) { - fun handle(userAction: QSTileUserAction, intent: Intent) { + fun handle(view: View?, intent: Intent) { val animationController: ActivityLaunchAnimator.Controller? = - userAction.view?.let { + view?.let { ActivityLaunchAnimator.Controller.fromView( it, InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE, diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/BaseQSTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/BaseQSTileViewModel.kt index c2a75fac60f5..bb4de808de79 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/BaseQSTileViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/BaseQSTileViewModel.kt @@ -92,7 +92,7 @@ constructor( .stateIn( tileScope, SharingStarted.WhileSubscribed(), - false, + true, ) private var currentLifeState: QSTileLifecycle = QSTileLifecycle.DEAD diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt new file mode 100644 index 000000000000..3fedbfc6671d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt @@ -0,0 +1,28 @@ +package com.android.systemui.qs.tiles.di + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.plugins.qs.QSFactory +import com.android.systemui.plugins.qs.QSTile +import com.android.systemui.qs.tiles.viewmodel.QSTileLifecycle +import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel +import com.android.systemui.qs.tiles.viewmodel.QSTileViewModelAdapter +import javax.inject.Inject +import javax.inject.Provider + +// TODO(b/http://b/299909989): Rename the factory after rollout +@SysUISingleton +class NewQSTileFactory +@Inject +constructor( + private val adapterFactory: QSTileViewModelAdapter.Factory, + private val tileMap: + Map<String, @JvmSuppressWildcards Provider<@JvmSuppressWildcards QSTileViewModel>>, +) : QSFactory { + + override fun createTile(tileSpec: String): QSTile? = + tileMap[tileSpec]?.let { + val tile = it.get() + tile.onLifecycle(QSTileLifecycle.ALIVE) + adapterFactory.create(tile) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt index a5eaac154230..019d3c0ee416 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt @@ -1,14 +1,13 @@ package com.android.systemui.qs.tiles.viewmodel -import android.graphics.drawable.Icon +import androidx.annotation.StringRes +import com.android.internal.logging.InstanceId +import com.android.systemui.common.shared.model.Icon import com.android.systemui.qs.pipeline.shared.TileSpec data class QSTileConfig( val tileSpec: TileSpec, val tileIcon: Icon, - val tileLabel: CharSequence, -// TODO(b/299908705): Fill necessary params -/* -val instanceId: InstanceId, - */ + @StringRes val tileLabelRes: Int, + val instanceId: InstanceId, ) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt index 53f9edfb954c..dc5c69080fd0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt @@ -1,18 +1,96 @@ package com.android.systemui.qs.tiles.viewmodel -import android.graphics.drawable.Icon +import android.service.quicksettings.Tile +import com.android.systemui.common.shared.model.Icon +/** + * Represents current a state of the tile to be displayed in on the view. Consider using + * [QSTileState.build] for better state creation experience and preset default values for certain + * fields. + * + * // TODO(b/http://b/299909989): Clean up legacy mappings after the transition + */ data class QSTileState( - val icon: Icon, + val icon: () -> Icon, val label: CharSequence, -// TODO(b/299908705): Fill necessary params -/* - val subtitle: CharSequence = "", - val activeState: ActivationState = Active, - val enabledState: Enabled = Enabled, - val loopIconAnimation: Boolean = false, - val secondaryIcon: Icon? = null, - val slashState: SlashState? = null, - val supportedActions: Collection<UserAction> = listOf(Click), clicks should be a default action -*/ -) + val activationState: ActivationState, + val secondaryLabel: CharSequence?, + val supportedActions: Set<UserAction>, + val contentDescription: CharSequence?, + val stateDescription: CharSequence?, + val sideViewIcon: SideViewIcon, + val enabledState: EnabledState, + val expandedAccessibilityClassName: String?, +) { + + companion object { + + fun build(icon: () -> Icon, label: CharSequence, build: Builder.() -> Unit): QSTileState = + Builder(icon, label).apply(build).build() + + fun build(icon: Icon, label: CharSequence, build: Builder.() -> Unit): QSTileState = + build({ icon }, label, build) + } + + enum class ActivationState(val legacyState: Int) { + // An unavailable state indicates that for some reason this tile is not currently available + // to the user, and will have no click action. The tile's icon will be tinted differently to + // reflect this state. + UNAVAILABLE(Tile.STATE_UNAVAILABLE), + // This represents a tile that is currently active. (e.g. wifi is connected, bluetooth is + // on, cast is casting). This is the default state. + ACTIVE(Tile.STATE_ACTIVE), + // This represents a tile that is currently in a disabled state but is still interactable. A + // disabled state indicates that the tile is not currently active (e.g. wifi disconnected or + // bluetooth disabled), but is still interactable by the user to modify this state. + INACTIVE(Tile.STATE_INACTIVE), + } + + /** + * Enabled tile behaves as usual where is disabled one is frozen and inactive in its current + * [ActivationState]. + */ + enum class EnabledState { + ENABLED, + DISABLED, + } + + enum class UserAction { + CLICK, + LONG_CLICK, + } + + sealed interface SideViewIcon { + data class Custom(val icon: Icon) : SideViewIcon + data object Chevron : SideViewIcon + data object None : SideViewIcon + } + + class Builder( + var icon: () -> Icon, + var label: CharSequence, + ) { + var activationState: ActivationState = ActivationState.INACTIVE + var secondaryLabel: CharSequence? = null + var supportedActions: Set<UserAction> = setOf(UserAction.CLICK) + var contentDescription: CharSequence? = null + var stateDescription: CharSequence? = null + var sideViewIcon: SideViewIcon = SideViewIcon.None + var enabledState: EnabledState = EnabledState.ENABLED + var expandedAccessibilityClassName: String? = null + + fun build(): QSTileState = + QSTileState( + icon, + label, + activationState, + secondaryLabel, + supportedActions, + contentDescription, + stateDescription, + sideViewIcon, + enabledState, + expandedAccessibilityClassName, + ) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt index f1f8f0152c67..0b232c28d3f4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt @@ -1,13 +1,11 @@ package com.android.systemui.qs.tiles.viewmodel -import android.content.Context import android.view.View sealed interface QSTileUserAction { - val context: Context val view: View? - class Click(override val context: Context, override val view: View?) : QSTileUserAction - class LongClick(override val context: Context, override val view: View?) : QSTileUserAction + class Click(override val view: View?) : QSTileUserAction + class LongClick(override val view: View?) : QSTileUserAction } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt new file mode 100644 index 000000000000..d4bdb77c2b41 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt @@ -0,0 +1,232 @@ +package com.android.systemui.qs.tiles.viewmodel + +import android.content.Context +import android.util.Log +import android.view.View +import androidx.annotation.GuardedBy +import com.android.internal.logging.InstanceId +import com.android.systemui.common.shared.model.Icon +import com.android.systemui.plugins.qs.QSTile +import com.android.systemui.qs.QSHost +import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon +import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import java.util.function.Supplier +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.cancelChildren +import kotlinx.coroutines.flow.collectIndexed +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch + +// TODO(b/http://b/299909989): Use QSTileViewModel directly after the rollout +class QSTileViewModelAdapter +@AssistedInject +constructor( + private val qsHost: QSHost, + @Assisted private val qsTileViewModel: QSTileViewModel, +) : QSTile { + + private val context + get() = qsHost.context + + @GuardedBy("callbacks") + private val callbacks: MutableCollection<QSTile.Callback> = mutableSetOf() + @GuardedBy("listeningClients") + private val listeningClients: MutableCollection<Any> = mutableSetOf() + + // Cancels the jobs when the adapter is no longer alive + private val adapterScope = CoroutineScope(SupervisorJob()) + // Cancels the jobs when clients stop listening + private val listeningScope = CoroutineScope(SupervisorJob()) + + init { + adapterScope.launch { + qsTileViewModel.isAvailable.collectIndexed { index, isAvailable -> + if (!isAvailable) { + qsHost.removeTile(tileSpec) + } + // qsTileViewModel.isAvailable flow often starts with isAvailable == true. That's + // why we only allow isAvailable == true once and throw an exception afterwards. + if (index > 0 && isAvailable) { + // See com.android.systemui.qs.pipeline.domain.model.AutoAddable for additional + // guidance on how to auto add your tile + throw UnsupportedOperationException("Turning on tile is not supported now") + } + } + } + + // QSTileHost doesn't call this when userId is initialized + userSwitch(qsHost.userId) + + if (DEBUG) { + Log.d(TAG, "Using new tiles for: $tileSpec") + } + } + + override fun isAvailable(): Boolean = qsTileViewModel.isAvailable.value + + override fun setTileSpec(tileSpec: String?) { + throw UnsupportedOperationException("Tile spec is immutable in new tiles") + } + + override fun refreshState() { + qsTileViewModel.forceUpdate() + } + + override fun addCallback(callback: QSTile.Callback?) { + callback ?: return + synchronized(callbacks) { callbacks.add(callback) } + } + + override fun removeCallback(callback: QSTile.Callback?) { + callback ?: return + synchronized(callbacks) { callbacks.remove(callback) } + } + + override fun removeCallbacks() { + synchronized(callbacks) { callbacks.clear() } + } + + override fun click(view: View?) { + if (isActionSupported(QSTileState.UserAction.CLICK)) { + qsTileViewModel.onActionPerformed(QSTileUserAction.Click(view)) + } + } + + override fun secondaryClick(view: View?) { + if (isActionSupported(QSTileState.UserAction.CLICK)) { + qsTileViewModel.onActionPerformed(QSTileUserAction.Click(view)) + } + } + + override fun longClick(view: View?) { + if (isActionSupported(QSTileState.UserAction.LONG_CLICK)) { + qsTileViewModel.onActionPerformed(QSTileUserAction.LongClick(view)) + } + } + + private fun isActionSupported(action: QSTileState.UserAction): Boolean = + qsTileViewModel.currentState?.supportedActions?.contains(action) == true + + override fun userSwitch(currentUser: Int) { + qsTileViewModel.onUserIdChanged(currentUser) + } + + @Deprecated( + "Not needed as {@link com.android.internal.logging.UiEvent} will use #getMetricsSpec", + replaceWith = ReplaceWith("getMetricsSpec"), + ) + override fun getMetricsCategory(): Int = 0 + + override fun setListening(client: Any?, listening: Boolean) { + client ?: return + synchronized(listeningClients) { + if (listening) { + listeningClients.add(client) + if (listeningClients.size == 1) { + qsTileViewModel.state + .map { mapState(context, it, qsTileViewModel.config) } + .onEach { legacyState -> + synchronized(callbacks) { + callbacks.forEach { it.onStateChanged(legacyState) } + } + } + .launchIn(listeningScope) + } + } else { + listeningClients.remove(client) + if (listeningClients.isEmpty()) { + listeningScope.coroutineContext.cancelChildren() + } + } + } + } + + override fun isListening(): Boolean = + synchronized(listeningClients) { listeningClients.isNotEmpty() } + + override fun setDetailListening(show: Boolean) { + // do nothing like QSTileImpl + } + + override fun destroy() { + adapterScope.cancel() + listeningScope.cancel() + qsTileViewModel.onLifecycle(QSTileLifecycle.DEAD) + } + + override fun getState(): QSTile.State? = + qsTileViewModel.currentState?.let { mapState(context, it, qsTileViewModel.config) } + + override fun getInstanceId(): InstanceId = qsTileViewModel.config.instanceId + override fun getTileLabel(): CharSequence = + context.getString(qsTileViewModel.config.tileLabelRes) + override fun getTileSpec(): String = qsTileViewModel.config.tileSpec.spec + + private companion object { + + const val DEBUG = false + const val TAG = "QSTileVMAdapter" + + fun mapState( + context: Context, + viewModelState: QSTileState, + config: QSTileConfig + ): QSTile.State = + // we have to use QSTile.BooleanState to support different side icons + // which are bound to instanceof QSTile.BooleanState in QSTileView. + QSTile.BooleanState().apply { + spec = config.tileSpec.spec + label = viewModelState.label + // This value is synthetic and doesn't have any meaning + value = false + + secondaryLabel = viewModelState.secondaryLabel + handlesLongClick = + viewModelState.supportedActions.contains(QSTileState.UserAction.LONG_CLICK) + + iconSupplier = Supplier { + when (val stateIcon = viewModelState.icon()) { + is Icon.Loaded -> DrawableIcon(stateIcon.drawable) + is Icon.Resource -> ResourceIcon.get(stateIcon.res) + } + } + state = viewModelState.activationState.legacyState + + contentDescription = viewModelState.contentDescription + stateDescription = viewModelState.stateDescription + + disabledByPolicy = viewModelState.enabledState == QSTileState.EnabledState.DISABLED + expandedAccessibilityClassName = viewModelState.expandedAccessibilityClassName + + when (viewModelState.sideViewIcon) { + is QSTileState.SideViewIcon.Custom -> { + sideViewCustomDrawable = + when (viewModelState.sideViewIcon.icon) { + is Icon.Loaded -> viewModelState.sideViewIcon.icon.drawable + is Icon.Resource -> + context.getDrawable(viewModelState.sideViewIcon.icon.res) + } + } + is QSTileState.SideViewIcon.Chevron -> { + forceExpandIcon = true + } + is QSTileState.SideViewIcon.None -> { + forceExpandIcon = false + } + } + } + } + + @AssistedFactory + interface Factory { + + fun create(qsTileViewModel: QSTileViewModel): QSTileViewModelAdapter + } +} diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java index 7cdb6553c47e..3501b6bc045e 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java @@ -41,10 +41,10 @@ import android.widget.Toast; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.UiEventLogger; -import com.android.systemui.res.R; import com.android.systemui.dagger.qualifiers.LongRunning; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.media.MediaProjectionCaptureTarget; +import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget; +import com.android.systemui.res.R; import com.android.systemui.screenrecord.ScreenMediaRecorder.ScreenMediaRecorderListener; import com.android.systemui.settings.UserContextProvider; import com.android.systemui.statusbar.phone.KeyguardDismissUtil; diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java index b80a01212ca0..3aab3bf62809 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java @@ -51,7 +51,7 @@ import android.util.Size; import android.view.Surface; import android.view.WindowManager; -import com.android.systemui.media.MediaProjectionCaptureTarget; +import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget; import java.io.Closeable; import java.io.File; diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java index f0ce8a465d0d..f2e94e94757f 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java @@ -18,7 +18,7 @@ package com.android.systemui.screenrecord; import static android.app.Activity.RESULT_OK; -import static com.android.systemui.media.MediaProjectionAppSelectorActivity.KEY_CAPTURE_TARGET; +import static com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorActivity.KEY_CAPTURE_TARGET; import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.INTERNAL; import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC; import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC_AND_INTERNAL; @@ -41,8 +41,8 @@ import android.widget.TextView; import androidx.annotation.Nullable; +import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget; import com.android.systemui.res.R; -import com.android.systemui.media.MediaProjectionCaptureTarget; import com.android.systemui.settings.UserContextProvider; import com.android.systemui.statusbar.phone.SystemUIDialog; diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt index b5b7043e37a0..a1d5d98ba9e9 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt @@ -32,10 +32,14 @@ import android.widget.ArrayAdapter import android.widget.Spinner import android.widget.Switch import androidx.annotation.LayoutRes -import com.android.systemui.res.R -import com.android.systemui.media.MediaProjectionAppSelectorActivity -import com.android.systemui.media.MediaProjectionCaptureTarget +import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget +import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorActivity +import com.android.systemui.mediaprojection.permission.BaseScreenSharePermissionDialog +import com.android.systemui.mediaprojection.permission.ENTIRE_SCREEN +import com.android.systemui.mediaprojection.permission.SINGLE_APP +import com.android.systemui.mediaprojection.permission.ScreenShareOption import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.res.R import com.android.systemui.settings.UserContextProvider /** Dialog to select screen recording options */ @@ -58,6 +62,7 @@ class ScreenRecordPermissionDialog( private lateinit var tapsView: View private lateinit var audioSwitch: Switch private lateinit var options: Spinner + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setDialogTitle(R.string.screenrecord_permission_dialog_title) @@ -177,6 +182,7 @@ class ScreenRecordPermissionDialog( ) private const val DELAY_MS: Long = 3000 private const val INTERVAL_MS: Long = 1000 + private fun createOptionList(): List<ScreenShareOption> { return listOf( ScreenShareOption( diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java index b7152370624e..6fa592c6dd78 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java @@ -30,12 +30,13 @@ import androidx.annotation.Nullable; import com.android.internal.logging.UiEventLogger; import com.android.settingslib.RestrictedLockUtils; import com.android.systemui.Gefingerpoken; -import com.android.systemui.res.R; import com.android.systemui.classifier.Classifier; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlagsClassic; import com.android.systemui.haptics.slider.SeekableSliderEventProducer; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.res.R; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.policy.BrightnessMirrorController; import com.android.systemui.util.ViewController; @@ -283,6 +284,7 @@ public class BrightnessSliderController extends ViewController<BrightnessSliderV private final VibratorHelper mVibratorHelper; private final SystemClock mSystemClock; private final CoroutineDispatcher mMainDispatcher; + private final ActivityStarter mActivityStarter; @Inject public Factory( @@ -291,14 +293,15 @@ public class BrightnessSliderController extends ViewController<BrightnessSliderV VibratorHelper vibratorHelper, SystemClock clock, FeatureFlagsClassic featureFlags, - @Main CoroutineDispatcher mainDispatcher - ) { + @Main CoroutineDispatcher mainDispatcher, + ActivityStarter activityStarter) { mFalsingManager = falsingManager; mUiEventLogger = uiEventLogger; mFeatureFlags = featureFlags; mVibratorHelper = vibratorHelper; mSystemClock = clock; mMainDispatcher = mainDispatcher; + mActivityStarter = activityStarter; } /** @@ -314,6 +317,8 @@ public class BrightnessSliderController extends ViewController<BrightnessSliderV int layout = getLayout(); BrightnessSliderView root = (BrightnessSliderView) LayoutInflater.from(context) .inflate(layout, viewRoot, false); + root.setActivityStarter(mActivityStarter); + BrightnessSliderHapticPlugin plugin; if (mFeatureFlags.isEnabled(HAPTIC_BRIGHTNESS_SLIDER)) { plugin = new BrightnessSliderHapticPluginImpl( diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java index c88549224183..5ecf07f5a264 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java @@ -33,6 +33,7 @@ import androidx.annotation.Nullable; import com.android.settingslib.RestrictedLockUtils; import com.android.systemui.Gefingerpoken; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.res.R; /** @@ -41,6 +42,7 @@ import com.android.systemui.res.R; */ public class BrightnessSliderView extends FrameLayout { + private ActivityStarter mActivityStarter; @NonNull private ToggleSeekBar mSlider; private DispatchTouchEventListener mListener; @@ -57,6 +59,10 @@ public class BrightnessSliderView extends FrameLayout { super(context, attrs); } + public void setActivityStarter(@NonNull ActivityStarter activityStarter) { + mActivityStarter = activityStarter; + } + // Inflated from quick_settings_brightness_dialog @Override protected void onFinishInflate() { @@ -65,6 +71,7 @@ public class BrightnessSliderView extends FrameLayout { mSlider = requireViewById(R.id.slider); mSlider.setAccessibilityLabel(getContentDescription().toString()); + mSlider.setActivityStarter(mActivityStarter); // Finds the progress drawable. Assumes brightness_progress_drawable.xml try { diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java index a5a0ae70045e..6ec10da28000 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java @@ -23,8 +23,9 @@ import android.view.MotionEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.SeekBar; +import androidx.annotation.NonNull; + import com.android.settingslib.RestrictedLockUtils; -import com.android.systemui.Dependency; import com.android.systemui.plugins.ActivityStarter; public class ToggleSeekBar extends SeekBar { @@ -32,6 +33,8 @@ public class ToggleSeekBar extends SeekBar { private RestrictedLockUtils.EnforcedAdmin mEnforcedAdmin = null; + private ActivityStarter mActivityStarter; + public ToggleSeekBar(Context context) { super(context); } @@ -49,7 +52,7 @@ public class ToggleSeekBar extends SeekBar { if (mEnforcedAdmin != null) { Intent intent = RestrictedLockUtils.getShowAdminSupportDetailsIntent( mContext, mEnforcedAdmin); - Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(intent, 0); + mActivityStarter.postStartActivityDismissingKeyguard(intent, 0); return true; } if (!isEnabled()) { @@ -74,4 +77,8 @@ public class ToggleSeekBar extends SeekBar { public void setEnforcedAdmin(RestrictedLockUtils.EnforcedAdmin admin) { mEnforcedAdmin = admin; } + + public void setActivityStarter(@NonNull ActivityStarter activityStarter) { + mActivityStarter = activityStarter; + } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt index 251cc168161c..ac8333ae84ad 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt @@ -129,6 +129,9 @@ constructor( combine(shadeExpansion, qsExpansion) { shadeExp, qsExp -> maxOf(shadeExp, qsExp) } .stateIn(scope, SharingStarted.Eagerly, 0f) + /** Whether either the shade or QS is fully expanded. */ + val isAnyFullyExpanded: Flow<Boolean> = anyExpansion.map { it >= 1f }.distinctUntilChanged() + /** Whether either the shade or QS is expanding from a fully collapsed state. */ val isAnyExpanding: Flow<Boolean> = anyExpansion diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index 8baab25e5c59..f616b91c4712 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -244,12 +244,16 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi } final float scaledImageWidth = drawableWidth * scaleToFitIconView; final float scaledImageHeight = drawableHeight * scaleToFitIconView; - // if the scaled image size <= mOriginalStatusBarIconSize, we don't need to enlarge it scaleToOriginalDrawingSize = Math.min( (float) mOriginalStatusBarIconSize / scaledImageWidth, (float) mOriginalStatusBarIconSize / scaledImageHeight); if (scaleToOriginalDrawingSize > 1.0f) { - scaleToOriginalDrawingSize = 1.0f; + // per b/296026932, if the scaled image size <= mOriginalStatusBarIconSize, we need + // to scale up the scaled image to fit in mOriginalStatusBarIconSize. But if both + // the raw drawable intrinsic width/height are less than mOriginalStatusBarIconSize, + // then we just scale up the scaled image back to the raw drawable size. + scaleToOriginalDrawingSize = Math.min( + scaleToOriginalDrawingSize, 1f / scaleToFitIconView); } } iconScale = scaleToOriginalDrawingSize; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/CallLayoutSetDataAsyncFactory.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/CallLayoutSetDataAsyncFactory.kt new file mode 100644 index 000000000000..4deebdb8de7d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/CallLayoutSetDataAsyncFactory.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.row + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import com.android.internal.widget.CallLayout +import javax.inject.Inject + +class CallLayoutSetDataAsyncFactory @Inject constructor() : NotifRemoteViewsFactory { + override fun instantiate( + row: ExpandableNotificationRow, + @NotificationRowContentBinder.InflationFlag layoutType: Int, + parent: View?, + name: String, + context: Context, + attrs: AttributeSet + ): View? = + if (name == CallLayout::class.java.name) + CallLayout(context, attrs).apply { setSetDataAsyncEnabled(true) } + else null +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java index 0239afc08ec5..3a59978d415c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java @@ -61,7 +61,8 @@ public abstract class NotificationRowModule { static Set<NotifRemoteViewsFactory> provideNotifRemoteViewsFactories( FeatureFlags featureFlags, PrecomputedTextViewFactory precomputedTextViewFactory, - BigPictureLayoutInflaterFactory bigPictureLayoutInflaterFactory + BigPictureLayoutInflaterFactory bigPictureLayoutInflaterFactory, + CallLayoutSetDataAsyncFactory callLayoutSetDataAsyncFactory ) { final Set<NotifRemoteViewsFactory> replacementFactories = new HashSet<>(); if (featureFlags.isEnabled(Flags.PRECOMPUTED_TEXT)) { @@ -70,6 +71,9 @@ public abstract class NotificationRowModule { if (featureFlags.isEnabled(Flags.BIGPICTURE_NOTIFICATION_LAZY_LOADING)) { replacementFactories.add(bigPictureLayoutInflaterFactory); } + if (featureFlags.isEnabled(Flags.CALL_LAYOUT_ASYNC_SET_DATA)) { + replacementFactories.add(callLayoutSetDataAsyncFactory); + } return replacementFactories; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java index 875a409c07f0..91b12ccf919a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java @@ -20,6 +20,9 @@ import static android.view.View.VISIBLE; import static com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.DEFAULT_HEADER_VISIBLE_AMOUNT; +import android.annotation.MainThread; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.Notification; import android.app.PendingIntent; import android.content.Context; @@ -34,8 +37,7 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; -import androidx.annotation.Nullable; - +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ContrastColorUtil; import com.android.internal.widget.NotificationActionListLayout; import com.android.systemui.Dependency; @@ -49,6 +51,8 @@ import com.android.systemui.statusbar.notification.TransformState; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.HybridNotificationView; +import java.util.function.Consumer; + /** * Wraps a notification view inflated from a template. */ @@ -66,9 +70,13 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp private int mContentHeight; private int mMinHeightHint; + @Nullable private NotificationActionListLayout mActions; - private ArraySet<PendingIntent> mCancelledPendingIntents = new ArraySet<>(); - private UiOffloadThread mUiOffloadThread; + // Holds list of pending intents that have been cancelled by now - we only keep hash codes + // to avoid holding full binder proxies for intents that may have been removed by now. + @NonNull + @VisibleForTesting + final ArraySet<Integer> mCancelledPendingIntents = new ArraySet<>(); private View mRemoteInputHistory; private boolean mCanHideHeader; private float mHeaderTranslation; @@ -147,6 +155,7 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp com.android.internal.R.dimen.notification_content_margin_top); } + @MainThread private void resolveTemplateViews(StatusBarNotification sbn) { mRightIcon = mView.findViewById(com.android.internal.R.id.right_icon); if (mRightIcon != null) { @@ -195,34 +204,57 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp return getLargeIcon(n); } + @MainThread private void updatePendingIntentCancellations() { if (mActions != null) { int numActions = mActions.getChildCount(); + final ArraySet<Integer> currentlyActivePendingIntents = new ArraySet<>(numActions); for (int i = 0; i < numActions; i++) { Button action = (Button) mActions.getChildAt(i); - performOnPendingIntentCancellation(action, () -> { - if (action.isEnabled()) { - action.setEnabled(false); - // The visual appearance doesn't look disabled enough yet, let's add the - // alpha as well. Since Alpha doesn't play nicely right now with the - // transformation, we rather blend it manually with the background color. - ColorStateList textColors = action.getTextColors(); - int[] colors = textColors.getColors(); - int[] newColors = new int[colors.length]; - float disabledAlpha = mView.getResources().getFloat( - com.android.internal.R.dimen.notification_action_disabled_alpha); - for (int j = 0; j < colors.length; j++) { - int color = colors[j]; - color = blendColorWithBackground(color, disabledAlpha); - newColors[j] = color; - } - ColorStateList newColorStateList = new ColorStateList( - textColors.getStates(), newColors); - action.setTextColor(newColorStateList); + PendingIntent pendingIntent = getPendingIntentForAction(action); + // Check if passed intent has already been cancelled in this class and immediately + // disable the action to avoid temporary race with enable/disable. + if (pendingIntent != null) { + int pendingIntentHashCode = getHashCodeForPendingIntent(pendingIntent); + currentlyActivePendingIntents.add(pendingIntentHashCode); + if (mCancelledPendingIntents.contains(pendingIntentHashCode)) { + disableActionView(action); } - }); + } + updatePendingIntentCancellationListener(action, pendingIntent); + } + + // This cleanup ensures that the size of this set doesn't grow into unreasonable sizes. + // There are scenarios where applications updated notifications with different + // PendingIntents which could cause this Set to grow to 1000+ elements. + mCancelledPendingIntents.retainAll(currentlyActivePendingIntents); + } + } + + @MainThread + private void updatePendingIntentCancellationListener(Button action, + @Nullable PendingIntent pendingIntent) { + ActionPendingIntentCancellationHandler cancellationHandler = null; + if (pendingIntent != null) { + // Attach listeners to handle intent cancellation to this view. + cancellationHandler = new ActionPendingIntentCancellationHandler(pendingIntent, action, + this::disableActionViewWithIntent); + action.addOnAttachStateChangeListener(cancellationHandler); + // Immediately fire the event if the view is already attached to register + // pending intent cancellation listener. + if (action.isAttachedToWindow()) { + cancellationHandler.onViewAttachedToWindow(action); } } + + // If the view has an old attached listener, remove it to avoid leaking intents. + ActionPendingIntentCancellationHandler previousHandler = + (ActionPendingIntentCancellationHandler) action.getTag( + R.id.pending_intent_listener_tag); + if (previousHandler != null) { + previousHandler.remove(); + } + action.setTag(R.id.pending_intent_listener_tag, cancellationHandler); } private int blendColorWithBackground(int color, float alpha) { @@ -231,42 +263,6 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp Color.red(color), Color.green(color), Color.blue(color)), resolveBackgroundColor()); } - private void performOnPendingIntentCancellation(View view, Runnable cancellationRunnable) { - PendingIntent pendingIntent = (PendingIntent) view.getTag( - com.android.internal.R.id.pending_intent_tag); - if (pendingIntent == null) { - return; - } - if (mCancelledPendingIntents.contains(pendingIntent)) { - cancellationRunnable.run(); - } else { - PendingIntent.CancelListener listener = (PendingIntent intent) -> { - mView.post(() -> { - mCancelledPendingIntents.add(pendingIntent); - cancellationRunnable.run(); - }); - }; - if (mUiOffloadThread == null) { - mUiOffloadThread = Dependency.get(UiOffloadThread.class); - } - if (view.isAttachedToWindow()) { - mUiOffloadThread.execute(() -> pendingIntent.registerCancelListener(listener)); - } - view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { - @Override - public void onViewAttachedToWindow(View v) { - mUiOffloadThread.execute(() -> pendingIntent.registerCancelListener(listener)); - } - - @Override - public void onViewDetachedFromWindow(View v) { - mUiOffloadThread.execute( - () -> pendingIntent.unregisterCancelListener(listener)); - } - }); - } - } - @Override public void onContentUpdated(ExpandableNotificationRow row) { // Reinspect the notification. Before the super call, because the super call also updates @@ -364,4 +360,141 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp } return extra + super.getExtraMeasureHeight(); } + + /** + * This finds Action view with a given intent and disables it. + * With maximum of 3 views, this is sufficiently fast to iterate on main thread every time. + */ + @MainThread + private void disableActionViewWithIntent(PendingIntent intent) { + mCancelledPendingIntents.add(getHashCodeForPendingIntent(intent)); + if (mActions != null) { + int numActions = mActions.getChildCount(); + for (int i = 0; i < numActions; i++) { + Button action = (Button) mActions.getChildAt(i); + PendingIntent pendingIntent = getPendingIntentForAction(action); + if (intent.equals(pendingIntent)) { + disableActionView(action); + } + } + } + } + + /** + * Disables Action view when, e.g., its PendingIntent is disabled. + */ + @MainThread + private void disableActionView(Button action) { + if (action.isEnabled()) { + action.setEnabled(false); + // The visual appearance doesn't look disabled enough yet, let's add the + // alpha as well. Since Alpha doesn't play nicely right now with the + // transformation, we rather blend it manually with the background color. + ColorStateList textColors = action.getTextColors(); + int[] colors = textColors.getColors(); + int[] newColors = new int[colors.length]; + float disabledAlpha = mView.getResources().getFloat( + com.android.internal.R.dimen.notification_action_disabled_alpha); + for (int j = 0; j < colors.length; j++) { + int color = colors[j]; + color = blendColorWithBackground(color, disabledAlpha); + newColors[j] = color; + } + ColorStateList newColorStateList = new ColorStateList( + textColors.getStates(), newColors); + action.setTextColor(newColorStateList); + } + } + + /** + * Returns the hashcode of underlying target of PendingIntent. We can get multiple + * Java PendingIntent wrapper objects pointing to the same cancelled PI in system_server. + * This makes sure we treat them equally. + */ + private static int getHashCodeForPendingIntent(PendingIntent pendingIntent) { + return System.identityHashCode(pendingIntent.getTarget().asBinder()); + } + + /** + * Returns PendingIntent contained in the action tag. May be null. + */ + @Nullable + private static PendingIntent getPendingIntentForAction(View action) { + return (PendingIntent) action.getTag(com.android.internal.R.id.pending_intent_tag); + } + + /** + * Registers listeners for pending intent cancellation when Action views are attached + * to window. + * It calls onCancelPendingIntentForActionView when a PendingIntent is cancelled. + */ + @VisibleForTesting + static final class ActionPendingIntentCancellationHandler + implements View.OnAttachStateChangeListener { + + @Nullable + private static UiOffloadThread sUiOffloadThread = null; + + @NonNull + private static UiOffloadThread getUiOffloadThread() { + if (sUiOffloadThread == null) { + sUiOffloadThread = Dependency.get(UiOffloadThread.class); + } + return sUiOffloadThread; + } + + private final View mView; + private final Consumer<PendingIntent> mOnCancelledCallback; + + private final PendingIntent mPendingIntent; + + ActionPendingIntentCancellationHandler(PendingIntent pendingIntent, View actionView, + Consumer<PendingIntent> onCancelled) { + this.mPendingIntent = pendingIntent; + this.mView = actionView; + this.mOnCancelledCallback = onCancelled; + } + + private final PendingIntent.CancelListener mCancelListener = + new PendingIntent.CancelListener() { + @Override + public void onCanceled(PendingIntent pendingIntent) { + mView.post(() -> { + mOnCancelledCallback.accept(pendingIntent); + // We don't need this listener anymore once the intent was cancelled. + remove(); + }); + } + }; + + @MainThread + @Override + public void onViewAttachedToWindow(View view) { + // This is safe to call multiple times with the same listener instance. + getUiOffloadThread().execute(() -> { + mPendingIntent.registerCancelListener(mCancelListener); + }); + } + + @MainThread + @Override + public void onViewDetachedFromWindow(View view) { + // This is safe to call multiple times with the same listener instance. + getUiOffloadThread().execute(() -> + mPendingIntent.unregisterCancelListener(mCancelListener)); + } + + /** + * Removes this listener from callbacks and releases the held PendingIntent. + */ + @MainThread + public void remove() { + mView.removeOnAttachStateChangeListener(this); + if (mView.getTag(R.id.pending_intent_listener_tag) == this) { + mView.setTag(R.id.pending_intent_listener_tag, null); + } + getUiOffloadThread().execute(() -> + mPendingIntent.unregisterCancelListener(mCancelListener)); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 727d649c8118..3c6d90dc08d2 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -135,6 +135,7 @@ import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.util.AlphaTintDrawableWrapper; import com.android.systemui.util.RoundedCornerProgressDrawable; +import com.android.systemui.util.settings.SecureSettings; import java.io.PrintWriter; import java.util.ArrayList; @@ -304,6 +305,8 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private @DevicePostureController.DevicePostureInt int mDevicePosture; private int mOrientation; private final FeatureFlags mFeatureFlags; + private final SecureSettings mSecureSettings; + private int mDialogTimeoutMillis; public VolumeDialogImpl( Context context, @@ -320,7 +323,8 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, DevicePostureController devicePostureController, Looper looper, DumpManager dumpManager, - FeatureFlags featureFlags) { + FeatureFlags featureFlags, + SecureSettings secureSettings) { mFeatureFlags = featureFlags; mContext = new ContextThemeWrapper(context, R.style.volume_dialog_theme); @@ -351,6 +355,8 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mUseBackgroundBlur = mContext.getResources().getBoolean(R.bool.config_volumeDialogUseBackgroundBlur); mInteractionJankMonitor = interactionJankMonitor; + mSecureSettings = secureSettings; + mDialogTimeoutMillis = DIALOG_TIMEOUT_MILLIS; dumpManager.registerDumpable("VolumeDialogImpl", this); @@ -515,6 +521,8 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mDialog.setContentView(R.layout.volume_dialog); mDialogView = mDialog.findViewById(R.id.volume_dialog); mDialogView.setAlpha(0); + mDialogTimeoutMillis = mSecureSettings.getInt(Settings.Secure.VOLUME_DIALOG_DISMISS_TIMEOUT, + DIALOG_TIMEOUT_MILLIS); mDialog.setCanceledOnTouchOutside(true); mDialog.setOnShowListener(dialog -> { mDialogView.getViewTreeObserver().addOnComputeInternalInsetsListener(this); @@ -527,7 +535,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, .alpha(1) .translationX(0) .setDuration(mDialogShowAnimationDurationMs) - .setListener(getJankListener(getDialogView(), TYPE_SHOW, DIALOG_TIMEOUT_MILLIS)) + .setListener(getJankListener(getDialogView(), TYPE_SHOW, mDialogTimeoutMillis)) .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator()) .withEndAction(() -> { if (!Prefs.getBoolean(mContext, Prefs.Key.TOUCHED_RINGER_TOGGLE, false)) { @@ -1514,7 +1522,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, AccessibilityManager.FLAG_CONTENT_TEXT | AccessibilityManager.FLAG_CONTENT_CONTROLS); } - return mAccessibilityMgr.getRecommendedTimeoutMillis(DIALOG_TIMEOUT_MILLIS, + return mAccessibilityMgr.getRecommendedTimeoutMillis(mDialogTimeoutMillis, AccessibilityManager.FLAG_CONTENT_CONTROLS); } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java index cc9f3e14216e..624691b19704 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java +++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java @@ -31,6 +31,7 @@ import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.volume.CsdWarningDialog; import com.android.systemui.volume.VolumeComponent; import com.android.systemui.volume.VolumeDialogComponent; @@ -63,7 +64,8 @@ public interface VolumeModule { CsdWarningDialog.Factory csdFactory, DevicePostureController devicePostureController, DumpManager dumpManager, - FeatureFlags featureFlags) { + FeatureFlags featureFlags, + SecureSettings secureSettings) { VolumeDialogImpl impl = new VolumeDialogImpl( context, volumeDialogController, @@ -79,7 +81,8 @@ public interface VolumeModule { devicePostureController, Looper.getMainLooper(), dumpManager, - featureFlags); + featureFlags, + secureSettings); impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false); impl.setAutomute(true); impl.setSilentMode(false); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java index ba3dbf0a0cb7..484b1194eb8b 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java @@ -20,8 +20,10 @@ import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.animation.LayoutTransition; import android.view.View; import android.view.ViewTreeObserver; +import android.widget.FrameLayout; import com.android.internal.jank.InteractionJankMonitor; import com.android.keyguard.logging.KeyguardLogger; @@ -44,6 +46,7 @@ import org.mockito.MockitoAnnotations; public class KeyguardStatusViewControllerBaseTest extends SysuiTestCase { @Mock protected KeyguardStatusView mKeyguardStatusView; + @Mock protected KeyguardSliceViewController mKeyguardSliceViewController; @Mock protected KeyguardClockSwitchController mKeyguardClockSwitchController; @Mock protected KeyguardStateController mKeyguardStateController; @@ -61,6 +64,10 @@ public class KeyguardStatusViewControllerBaseTest extends SysuiTestCase { protected KeyguardStatusViewController mController; + @Mock protected KeyguardClockSwitch mKeyguardClockSwitch; + @Mock protected FrameLayout mMediaHostContainer; + @Mock protected LayoutTransition mMediaLayoutTransition; + @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -93,6 +100,8 @@ public class KeyguardStatusViewControllerBaseTest extends SysuiTestCase { }; when(mKeyguardStatusView.getViewTreeObserver()).thenReturn(mViewTreeObserver); + + when(mKeyguardClockSwitchController.getView()).thenReturn(mKeyguardClockSwitch); } protected void givenViewAttached() { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java index b8b0198f94df..e4e2b0a8d89f 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java @@ -18,14 +18,18 @@ package com.android.keyguard; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.animation.LayoutTransition; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.view.View; +import com.android.systemui.res.R; import com.android.systemui.plugins.ClockConfig; import com.android.systemui.plugins.ClockController; import com.android.systemui.statusbar.notification.AnimatableProperty; @@ -124,4 +128,112 @@ public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControll mController.onDestroy(); verify(mDumpManager, times(1)).unregisterDumpable(eq(mController.getInstanceName())); } + + @Test + public void onInit_addsOnLayoutChangeListenerToClockSwitch() { + when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn( + mMediaHostContainer); + + mController.onInit(); + + ArgumentCaptor<View.OnLayoutChangeListener> captor = + ArgumentCaptor.forClass(View.OnLayoutChangeListener.class); + verify(mKeyguardClockSwitch).addOnLayoutChangeListener(captor.capture()); + } + + @Test + public void onInit_addsOnLayoutChangeListenerToMediaHostContainer() { + when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn( + mMediaHostContainer); + + mController.onInit(); + + ArgumentCaptor<View.OnLayoutChangeListener> captor = + ArgumentCaptor.forClass(View.OnLayoutChangeListener.class); + verify(mMediaHostContainer).addOnLayoutChangeListener(captor.capture()); + } + + @Test + public void clockSwitchHeightChanged_mediaChangingLayoutTransitionEnabled() { + when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn( + mMediaHostContainer); + + mController.onInit(); + + ArgumentCaptor<View.OnLayoutChangeListener> captor = + ArgumentCaptor.forClass(View.OnLayoutChangeListener.class); + verify(mKeyguardClockSwitch).addOnLayoutChangeListener(captor.capture()); + + // Above here is the same as `onInit_addsOnLayoutChangeListenerToClockSwitch`. + // Below here is the actual test. + + View.OnLayoutChangeListener listener = captor.getValue(); + + mController.setSplitShadeEnabled(true); + when(mKeyguardClockSwitch.getSplitShadeCentered()).thenReturn(false); + when(mKeyguardUpdateMonitor.isKeyguardVisible()).thenReturn(true); + when(mMediaHostContainer.getVisibility()).thenReturn(View.VISIBLE); + when(mMediaHostContainer.getHeight()).thenReturn(200); + when(mMediaHostContainer.getLayoutTransition()).thenReturn(mMediaLayoutTransition); + + when(mKeyguardClockSwitch.getHeight()).thenReturn(0); + listener.onLayoutChange(mKeyguardClockSwitch, /* left= */ 0, /* top= */ 0, /* right= */ + 0, /* bottom= */ 0, /* oldLeft= */ 0, /* oldTop= */ 0, /* oldRight= */ + 0, /* oldBottom = */ 200); + verify(mMediaLayoutTransition).enableTransitionType(LayoutTransition.CHANGING); + } + + @Test + public void clockSwitchHeightNotChanged_mediaChangingLayoutTransitionNotEnabled() { + when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn( + mMediaHostContainer); + + mController.onInit(); + + ArgumentCaptor<View.OnLayoutChangeListener> captor = + ArgumentCaptor.forClass(View.OnLayoutChangeListener.class); + verify(mKeyguardClockSwitch).addOnLayoutChangeListener(captor.capture()); + + // Above here is the same as `onInit_addsOnLayoutChangeListenerToClockSwitch`. + // Below here is the actual test. + + View.OnLayoutChangeListener listener = captor.getValue(); + + mController.setSplitShadeEnabled(true); + when(mKeyguardClockSwitch.getSplitShadeCentered()).thenReturn(false); + when(mKeyguardUpdateMonitor.isKeyguardVisible()).thenReturn(true); + when(mMediaHostContainer.getVisibility()).thenReturn(View.VISIBLE); + when(mMediaHostContainer.getHeight()).thenReturn(200); + when(mMediaHostContainer.getLayoutTransition()).thenReturn(mMediaLayoutTransition); + + when(mKeyguardClockSwitch.getHeight()).thenReturn(200); + listener.onLayoutChange(mKeyguardClockSwitch, /* left= */ 0, /* top= */ 0, /* right= */ + 0, /* bottom= */ 0, /* oldLeft= */ 0, /* oldTop= */ 0, /* oldRight= */ + 0, /* oldBottom = */ 200); + verify(mMediaLayoutTransition, never()).enableTransitionType(LayoutTransition.CHANGING); + } + + @Test + public void onMediaHostContainerLayout_disablesChangingLayoutTransition() { + when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn( + mMediaHostContainer); + + mController.onInit(); + + ArgumentCaptor<View.OnLayoutChangeListener> captor = + ArgumentCaptor.forClass(View.OnLayoutChangeListener.class); + verify(mMediaHostContainer).addOnLayoutChangeListener(captor.capture()); + + // Above here is the same as `onInit_addsOnLayoutChangeListenerToMediaHostContainer`. + // Below here is the actual test. + + View.OnLayoutChangeListener listener = captor.getValue(); + + when(mMediaHostContainer.getLayoutTransition()).thenReturn(mMediaLayoutTransition); + + when(mMediaLayoutTransition.isTransitionTypeEnabled(LayoutTransition.CHANGING)).thenReturn( + true); + listener.onLayoutChange(mMediaHostContainer, 1, 2, 3, 4, 1, 2, 3, 4); + verify(mMediaLayoutTransition).disableTransitionType(LayoutTransition.CHANGING); + } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt index 86439e557f8b..58d372c68c55 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt @@ -1,5 +1,6 @@ package com.android.keyguard +import android.animation.LayoutTransition import android.test.suitebuilder.annotation.SmallTest import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper @@ -35,6 +36,20 @@ class KeyguardStatusViewTest : SysuiTestCase() { } @Test + fun mediaViewHasLayoutTransitionInDisabledState() { + val layoutTransition = (mediaView as ViewGroup).layoutTransition + assertThat(layoutTransition).isNotNull() + assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.CHANGE_APPEARING)) + .isFalse() + assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.CHANGE_DISAPPEARING)) + .isFalse() + assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.APPEARING)).isFalse() + assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.DISAPPEARING)) + .isFalse() + assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.CHANGING)).isFalse() + } + + @Test fun setChildrenTranslationYExcludingMediaView_mediaViewIsNotTranslated() { val translationY = 1234f diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java index b595e8de3bad..79411f427f1f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -66,6 +66,7 @@ import com.android.systemui.qs.external.TileServiceKey; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository; import com.android.systemui.qs.tileimpl.QSTileImpl; +import com.android.systemui.qs.tiles.di.NewQSTileFactory; import com.android.systemui.settings.UserFileManager; import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.ShadeController; @@ -77,6 +78,8 @@ import com.android.systemui.util.settings.FakeSettings; import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.time.FakeSystemClock; +import dagger.Lazy; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -102,8 +105,6 @@ public class QSTileHostTest extends SysuiTestCase { private static final String SETTING = QSHost.TILES_SETTING; @Mock - private QSFactory mDefaultFactory; - @Mock private PluginManager mPluginManager; @Mock private TunerService mTunerService; @@ -117,7 +118,6 @@ public class QSTileHostTest extends SysuiTestCase { private CustomTile mCustomTile; @Mock private UserTracker mUserTracker; - private SecureSettings mSecureSettings; @Mock private CustomTileStatePersister mCustomTileStatePersister; @Mock @@ -127,6 +127,10 @@ public class QSTileHostTest extends SysuiTestCase { @Mock private UserFileManager mUserFileManager; + private SecureSettings mSecureSettings; + + private QSFactory mDefaultFactory; + private SparseArray<SharedPreferences> mSharedPreferencesByUser; private FakeFeatureFlags mFeatureFlags; @@ -144,6 +148,8 @@ public class QSTileHostTest extends SysuiTestCase { mFeatureFlags.set(Flags.QS_PIPELINE_NEW_HOST, false); mFeatureFlags.set(Flags.QS_PIPELINE_AUTO_ADD, false); + // TODO(b/299909337): Add test checking the new factory is used when the flag is on + mFeatureFlags.set(Flags.QS_PIPELINE_NEW_TILES, false); mQSPipelineFlagsRepository = new QSPipelineFlagsRepository(mFeatureFlags); mMainExecutor = new FakeExecutor(new FakeSystemClock()); @@ -164,7 +170,8 @@ public class QSTileHostTest extends SysuiTestCase { mSecureSettings = new FakeSettings(); saveSetting(""); - mQSTileHost = new TestQSTileHost(mContext, mDefaultFactory, mMainExecutor, + setUpTileFactory(); + mQSTileHost = new TestQSTileHost(mContext, () -> null, mDefaultFactory, mMainExecutor, mPluginManager, mTunerService, () -> mAutoTiles, mShadeController, mQSLogger, mUserTracker, mSecureSettings, mCustomTileStatePersister, mTileLifecycleManagerFactory, mUserFileManager, mQSPipelineFlagsRepository); @@ -178,7 +185,6 @@ public class QSTileHostTest extends SysuiTestCase { mMainExecutor.runAllReady(); } }, mUserTracker.getUserId()); - setUpTileFactory(); } private void saveSetting(String value) { @@ -191,32 +197,29 @@ public class QSTileHostTest extends SysuiTestCase { } private void setUpTileFactory() { - // Only create this kind of tiles - when(mDefaultFactory.createTile(anyString())).thenAnswer( - invocation -> { - String spec = invocation.getArgument(0); - if ("spec1".equals(spec)) { - return new TestTile1(mQSTileHost); - } else if ("spec2".equals(spec)) { - return new TestTile2(mQSTileHost); - } else if ("spec3".equals(spec)) { - return new TestTile3(mQSTileHost); - } else if ("na".equals(spec)) { - return new NotAvailableTile(mQSTileHost); - } else if (CUSTOM_TILE_SPEC.equals(spec)) { - QSTile tile = mCustomTile; - QSTile.State s = mock(QSTile.State.class); - s.spec = spec; - when(mCustomTile.getState()).thenReturn(s); - return tile; - } else if ("internet".equals(spec) - || "wifi".equals(spec) - || "cell".equals(spec)) { - return new TestTile1(mQSTileHost); - } else { - return null; - } - }); + mDefaultFactory = new FakeQSFactory(spec -> { + if ("spec1".equals(spec)) { + return new TestTile1(mQSTileHost); + } else if ("spec2".equals(spec)) { + return new TestTile2(mQSTileHost); + } else if ("spec3".equals(spec)) { + return new TestTile3(mQSTileHost); + } else if ("na".equals(spec)) { + return new NotAvailableTile(mQSTileHost); + } else if (CUSTOM_TILE_SPEC.equals(spec)) { + QSTile tile = mCustomTile; + QSTile.State s = mock(QSTile.State.class); + s.spec = spec; + when(mCustomTile.getState()).thenReturn(s); + return tile; + } else if ("internet".equals(spec) + || "wifi".equals(spec) + || "cell".equals(spec)) { + return new TestTile1(mQSTileHost); + } else { + return null; + } + }); when(mCustomTile.isAvailable()).thenReturn(true); } @@ -703,7 +706,7 @@ public class QSTileHostTest extends SysuiTestCase { } private class TestQSTileHost extends QSTileHost { - TestQSTileHost(Context context, + TestQSTileHost(Context context, Lazy<NewQSTileFactory> newQSTileFactoryProvider, QSFactory defaultFactory, Executor mainExecutor, PluginManager pluginManager, TunerService tunerService, Provider<AutoTileManager> autoTiles, @@ -712,7 +715,7 @@ public class QSTileHostTest extends SysuiTestCase { CustomTileStatePersister customTileStatePersister, TileLifecycleManager.Factory tileLifecycleManagerFactory, UserFileManager userFileManager, QSPipelineFlagsRepository featureFlags) { - super(context, defaultFactory, mainExecutor, pluginManager, + super(context, newQSTileFactoryProvider, defaultFactory, mainExecutor, pluginManager, tunerService, autoTiles, shadeController, qsLogger, userTracker, secureSettings, customTileStatePersister, tileLifecycleManagerFactory, userFileManager, featureFlags); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java index bde30382ba05..d3cd26bcd3cb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java @@ -124,6 +124,7 @@ public class TileQueryHelperTest extends SysuiTestCase { if (FACTORY_TILES.contains(spec)) { FakeQSTile tile = new FakeQSTile(mBgExecutor, mMainExecutor); tile.setState(mState); + tile.setTileSpec(spec); return tile; } else { return null; @@ -284,7 +285,10 @@ public class TileQueryHelperTest extends SysuiTestCase { Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.QS_TILES, null); QSTile t = mock(QSTile.class); - when(mQSHost.createTile("hotspot")).thenReturn(t); + when(mQSHost.createTile("hotspot")).thenAnswer(invocation -> { + t.setTileSpec("hotspot"); + return t; + }); mContext.getOrCreateTestableResources().addOverride(R.string.quick_settings_tiles_stock, "hotspot"); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt index dc1b9c4d0d14..a7505240caeb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt @@ -46,6 +46,7 @@ import com.android.systemui.qs.pipeline.domain.model.TileModel import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger +import com.android.systemui.qs.tiles.di.NewQSTileFactory import com.android.systemui.qs.toProto import com.android.systemui.settings.UserTracker import com.android.systemui.user.data.repository.FakeUserRepository @@ -91,6 +92,8 @@ class CurrentTilesInteractorImplTest : SysuiTestCase() { @Mock private lateinit var logger: QSPipelineLogger + @Mock private lateinit var newQSTileFactory: NewQSTileFactory + private val testDispatcher = StandardTestDispatcher() private val testScope = TestScope(testDispatcher) @@ -105,6 +108,8 @@ class CurrentTilesInteractorImplTest : SysuiTestCase() { featureFlags.set(Flags.QS_PIPELINE_NEW_HOST, true) featureFlags.set(Flags.QS_PIPELINE_AUTO_ADD, true) + // TODO(b/299909337): Add test checking the new factory is used when the flag is on + featureFlags.set(Flags.QS_PIPELINE_NEW_TILES, true) userRepository.setUserInfos(listOf(USER_INFO_0, USER_INFO_1)) @@ -117,6 +122,7 @@ class CurrentTilesInteractorImplTest : SysuiTestCase() { userRepository = userRepository, customTileStatePersister = customTileStatePersister, tileFactory = tileFactory, + newQSTileFactory = { newQSTileFactory }, customTileAddedRepository = customTileAddedRepository, tileLifecycleManagerFactory = tileLifecycleManagerFactory, userTracker = userTracker, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt index 5630b9d3b292..2e6b50b637dd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt @@ -1,6 +1,6 @@ package com.android.systemui.qs.pipeline.domain.interactor -import android.testing.AndroidTestingRunner +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.RoboPilotTest import com.android.systemui.SysuiTestCase @@ -21,7 +21,7 @@ import org.junit.runner.RunWith import org.mockito.MockitoAnnotations @RoboPilotTest -@RunWith(AndroidTestingRunner::class) +@RunWith(AndroidJUnit4::class) @SmallTest class RestoreReconciliationInteractorTest : SysuiTestCase() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/QSTileIntentUserActionHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/QSTileIntentUserActionHandlerTest.kt index 47b4244e0910..077c81343c83 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/QSTileIntentUserActionHandlerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/QSTileIntentUserActionHandlerTest.kt @@ -6,7 +6,6 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.plugins.ActivityStarter import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserActionHandler -import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -34,7 +33,7 @@ class QSTileIntentUserActionHandlerTest : SysuiTestCase() { fun testPassesIntentToStarter() { val intent = Intent("test.ACTION") - underTest.handle(QSTileUserAction.Click(context, null), intent) + underTest.handle(null, intent) verify(activityStarted).postStartActivityDismissingKeyguard(eq(intent), eq(0), any()) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt index 643866e3cade..eacb08010159 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt @@ -1,11 +1,14 @@ package com.android.systemui.qs.tiles.viewmodel -import android.graphics.drawable.Icon +import android.graphics.drawable.ShapeDrawable import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.MediumTest +import com.android.internal.logging.InstanceId import com.android.systemui.RoboPilotTest import com.android.systemui.SysuiTestCase +import com.android.systemui.common.shared.model.ContentDescription +import com.android.systemui.common.shared.model.Icon import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.tiles.base.interactor.FakeQSTileDataInteractor import com.android.systemui.qs.tiles.base.interactor.FakeQSTileUserActionInteractor @@ -71,20 +74,21 @@ class QSTileViewModelInterfaceComplianceTest : SysuiTestCase() { fakeQSTileUserActionInteractor, fakeQSTileDataInteractor, object : QSTileDataToStateMapper<Any> { - override fun map(config: QSTileConfig, data: Any): QSTileState { - return QSTileState(config.tileIcon, config.tileLabel) - } + override fun map(config: QSTileConfig, data: Any): QSTileState = + QSTileState.build(Icon.Resource(0, ContentDescription.Resource(0)), "") {} }, testCoroutineDispatcher, tileScope = scope.backgroundScope, ) {} private companion object { + val TEST_QS_TILE_CONFIG = QSTileConfig( TileSpec.create("default"), - Icon.createWithContentUri(""), - "", + Icon.Loaded(ShapeDrawable(), null), + 0, + InstanceId.fakeInstanceId(0), ) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java index 59b595393749..a2aed988a423 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java @@ -41,7 +41,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.UiEventLogger; import com.android.systemui.SysuiTestCase; -import com.android.systemui.media.MediaProjectionCaptureTarget; +import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.settings.UserContextProvider; import com.android.systemui.statusbar.SysuiStatusBarStateController; diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt index d470d24489af..3ae1f35b8134 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt @@ -22,11 +22,13 @@ import android.testing.TestableLooper import android.view.View import android.widget.Spinner import androidx.test.filters.SmallTest -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags +import com.android.systemui.mediaprojection.permission.ENTIRE_SCREEN +import com.android.systemui.mediaprojection.permission.SINGLE_APP import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.res.R import com.android.systemui.settings.UserContextProvider import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat @@ -35,8 +37,8 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock -import org.mockito.MockitoAnnotations import org.mockito.Mockito.`when` as whenever +import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidTestingRunner::class) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt index 48665fe0c9b0..e71473681211 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt @@ -15,6 +15,7 @@ */ package com.android.systemui.shared.clocks +import android.content.ComponentName import android.content.ContentResolver import android.content.Context import android.graphics.drawable.Drawable @@ -28,12 +29,11 @@ import com.android.systemui.plugins.ClockId import com.android.systemui.plugins.ClockMetadata import com.android.systemui.plugins.ClockProviderPlugin import com.android.systemui.plugins.ClockSettings -import com.android.systemui.plugins.PluginListener import com.android.systemui.plugins.PluginLifecycleManager +import com.android.systemui.plugins.PluginListener import com.android.systemui.plugins.PluginManager import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.eq -import com.android.systemui.util.mockito.mock import junit.framework.Assert.assertEquals import junit.framework.Assert.fail import kotlinx.coroutines.CoroutineDispatcher @@ -46,6 +46,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.never +import org.mockito.Mockito.spy import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever @@ -66,7 +67,6 @@ class ClockRegistryTest : SysuiTestCase() { @Mock private lateinit var mockDefaultClock: ClockController @Mock private lateinit var mockThumbnail: Drawable @Mock private lateinit var mockContentResolver: ContentResolver - @Mock private lateinit var mockPluginLifecycle: PluginLifecycleManager<ClockProviderPlugin> private lateinit var fakeDefaultProvider: FakeClockPlugin private lateinit var pluginListener: PluginListener<ClockProviderPlugin> private lateinit var registry: ClockRegistry @@ -84,6 +84,41 @@ class ClockRegistryTest : SysuiTestCase() { } } + private class FakeLifecycle( + private val tag: String, + private val plugin: ClockProviderPlugin?, + ) : PluginLifecycleManager<ClockProviderPlugin> { + var onLoad: (() -> Unit)? = null + var onUnload: (() -> Unit)? = null + + private var mIsLoaded: Boolean = true + override fun isLoaded() = mIsLoaded + override fun getPlugin(): ClockProviderPlugin? = if (isLoaded) plugin else null + + var mComponentName = ComponentName("Package[$tag]", "Class[$tag]") + override fun toString() = "Manager[$tag]" + override fun getPackage(): String = mComponentName.getPackageName() + override fun getComponentName(): ComponentName = mComponentName + + private var isDebug: Boolean = false + override fun getIsDebug(): Boolean = isDebug + override fun setIsDebug(value: Boolean) { isDebug = value } + + override fun loadPlugin() { + if (!mIsLoaded) { + mIsLoaded = true + onLoad?.invoke() + } + } + + override fun unloadPlugin() { + if (mIsLoaded) { + mIsLoaded = false + onUnload?.invoke() + } + } + } + private class FakeClockPlugin : ClockProviderPlugin { private val metadata = mutableListOf<ClockMetadata>() private val createCallbacks = mutableMapOf<ClockId, (ClockId) -> ClockController>() @@ -150,13 +185,15 @@ class ClockRegistryTest : SysuiTestCase() { val plugin1 = FakeClockPlugin() .addClock("clock_1", "clock 1") .addClock("clock_2", "clock 2") + val lifecycle1 = FakeLifecycle("1", plugin1) val plugin2 = FakeClockPlugin() .addClock("clock_3", "clock 3") .addClock("clock_4", "clock 4") + val lifecycle2 = FakeLifecycle("2", plugin2) - pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle) - pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle) + pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1) + pluginListener.onPluginLoaded(plugin2, mockContext, lifecycle2) val list = registry.getClocks() assertEquals( list.toSet(), @@ -178,18 +215,18 @@ class ClockRegistryTest : SysuiTestCase() { @Test fun clockIdConflict_ErrorWithoutCrash_unloadDuplicate() { - val mockPluginLifecycle1 = mock<PluginLifecycleManager<ClockProviderPlugin>>() val plugin1 = FakeClockPlugin() .addClock("clock_1", "clock 1", { mockClock }, { mockThumbnail }) .addClock("clock_2", "clock 2", { mockClock }, { mockThumbnail }) + val lifecycle1 = spy(FakeLifecycle("1", plugin1)) - val mockPluginLifecycle2 = mock<PluginLifecycleManager<ClockProviderPlugin>>() val plugin2 = FakeClockPlugin() .addClock("clock_1", "clock 1") .addClock("clock_2", "clock 2") + val lifecycle2 = spy(FakeLifecycle("2", plugin2)) - pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle1) - pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle2) + pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1) + pluginListener.onPluginLoaded(plugin2, mockContext, lifecycle2) val list = registry.getClocks() assertEquals( list.toSet(), @@ -204,8 +241,8 @@ class ClockRegistryTest : SysuiTestCase() { assertEquals(registry.createExampleClock("clock_2"), mockClock) assertEquals(registry.getClockThumbnail("clock_1"), mockThumbnail) assertEquals(registry.getClockThumbnail("clock_2"), mockThumbnail) - verify(mockPluginLifecycle1, never()).unloadPlugin() - verify(mockPluginLifecycle2, times(2)).unloadPlugin() + verify(lifecycle1, never()).unloadPlugin() + verify(lifecycle2, times(2)).unloadPlugin() } @Test @@ -213,14 +250,16 @@ class ClockRegistryTest : SysuiTestCase() { val plugin1 = FakeClockPlugin() .addClock("clock_1", "clock 1") .addClock("clock_2", "clock 2") + val lifecycle1 = spy(FakeLifecycle("1", plugin1)) val plugin2 = FakeClockPlugin() .addClock("clock_3", "clock 3", { mockClock }) .addClock("clock_4", "clock 4") + val lifecycle2 = spy(FakeLifecycle("2", plugin2)) registry.applySettings(ClockSettings("clock_3", null)) - pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle) - pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle) + pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1) + pluginListener.onPluginLoaded(plugin2, mockContext, lifecycle2) val clock = registry.createCurrentClock() assertEquals(mockClock, clock) @@ -231,17 +270,19 @@ class ClockRegistryTest : SysuiTestCase() { val plugin1 = FakeClockPlugin() .addClock("clock_1", "clock 1") .addClock("clock_2", "clock 2") + val lifecycle1 = spy(FakeLifecycle("1", plugin1)) val plugin2 = FakeClockPlugin() .addClock("clock_3", "clock 3", { mockClock }) .addClock("clock_4", "clock 4") + val lifecycle2 = spy(FakeLifecycle("2", plugin2)) registry.applySettings(ClockSettings("clock_3", null)) - pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle) + pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1) assertEquals(DEFAULT_CLOCK_ID, registry.activeClockId) - pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle) + pluginListener.onPluginLoaded(plugin2, mockContext, lifecycle2) assertEquals("clock_3", registry.activeClockId) } @@ -250,15 +291,17 @@ class ClockRegistryTest : SysuiTestCase() { val plugin1 = FakeClockPlugin() .addClock("clock_1", "clock 1") .addClock("clock_2", "clock 2") + val lifecycle1 = spy(FakeLifecycle("1", plugin1)) val plugin2 = FakeClockPlugin() .addClock("clock_3", "clock 3") .addClock("clock_4", "clock 4") + val lifecycle2 = spy(FakeLifecycle("2", plugin2)) registry.applySettings(ClockSettings("clock_3", null)) - pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle) - pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle) - pluginListener.onPluginUnloaded(plugin2, mockPluginLifecycle) + pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1) + pluginListener.onPluginLoaded(plugin2, mockContext, lifecycle2) + pluginListener.onPluginUnloaded(plugin2, lifecycle2) val clock = registry.createCurrentClock() assertEquals(clock, mockDefaultClock) @@ -266,15 +309,15 @@ class ClockRegistryTest : SysuiTestCase() { @Test fun pluginRemoved_clockAndListChanged() { - val mockPluginLifecycle1 = mock<PluginLifecycleManager<ClockProviderPlugin>>() val plugin1 = FakeClockPlugin() .addClock("clock_1", "clock 1") .addClock("clock_2", "clock 2") + val lifecycle1 = spy(FakeLifecycle("1", plugin1)) - val mockPluginLifecycle2 = mock<PluginLifecycleManager<ClockProviderPlugin>>() val plugin2 = FakeClockPlugin() .addClock("clock_3", "clock 3", { mockClock }) .addClock("clock_4", "clock 4") + val lifecycle2 = spy(FakeLifecycle("2", plugin2)) var changeCallCount = 0 var listChangeCallCount = 0 @@ -288,32 +331,32 @@ class ClockRegistryTest : SysuiTestCase() { assertEquals(1, changeCallCount) assertEquals(0, listChangeCallCount) - pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle1) + pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1) scheduler.runCurrent() assertEquals(1, changeCallCount) assertEquals(1, listChangeCallCount) - pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle2) + pluginListener.onPluginLoaded(plugin2, mockContext, lifecycle2) scheduler.runCurrent() assertEquals(2, changeCallCount) assertEquals(2, listChangeCallCount) - pluginListener.onPluginUnloaded(plugin1, mockPluginLifecycle1) + pluginListener.onPluginUnloaded(plugin1, lifecycle1) scheduler.runCurrent() assertEquals(2, changeCallCount) assertEquals(2, listChangeCallCount) - pluginListener.onPluginUnloaded(plugin2, mockPluginLifecycle2) + pluginListener.onPluginUnloaded(plugin2, lifecycle2) scheduler.runCurrent() assertEquals(3, changeCallCount) assertEquals(2, listChangeCallCount) - pluginListener.onPluginDetached(mockPluginLifecycle1) + pluginListener.onPluginDetached(lifecycle1) scheduler.runCurrent() assertEquals(3, changeCallCount) assertEquals(3, listChangeCallCount) - pluginListener.onPluginDetached(mockPluginLifecycle2) + pluginListener.onPluginDetached(lifecycle2) scheduler.runCurrent() assertEquals(3, changeCallCount) assertEquals(4, listChangeCallCount) @@ -321,8 +364,9 @@ class ClockRegistryTest : SysuiTestCase() { @Test fun unknownPluginAttached_clockAndListUnchanged_loadRequested() { - val mockPluginLifecycle = mock<PluginLifecycleManager<ClockProviderPlugin>>() - whenever(mockPluginLifecycle.getPackage()).thenReturn("some.other.package") + val lifecycle = FakeLifecycle("", null).apply { + mComponentName = ComponentName("some.other.package", "SomeClass") + } var changeCallCount = 0 var listChangeCallCount = 0 @@ -331,7 +375,7 @@ class ClockRegistryTest : SysuiTestCase() { override fun onAvailableClocksChanged() { listChangeCallCount++ } }) - assertEquals(true, pluginListener.onPluginAttached(mockPluginLifecycle)) + assertEquals(true, pluginListener.onPluginAttached(lifecycle)) scheduler.runCurrent() assertEquals(0, changeCallCount) assertEquals(0, listChangeCallCount) @@ -339,10 +383,12 @@ class ClockRegistryTest : SysuiTestCase() { @Test fun knownPluginAttached_clockAndListChanged_notLoaded() { - val mockPluginLifecycle1 = mock<PluginLifecycleManager<ClockProviderPlugin>>() - whenever(mockPluginLifecycle1.getPackage()).thenReturn("com.android.systemui.clocks.metro") - val mockPluginLifecycle2 = mock<PluginLifecycleManager<ClockProviderPlugin>>() - whenever(mockPluginLifecycle2.getPackage()).thenReturn("com.android.systemui.clocks.bignum") + val lifecycle1 = FakeLifecycle("Metro", null).apply { + mComponentName = ComponentName("com.android.systemui.clocks.metro", "MetroClock") + } + val lifecycle2 = FakeLifecycle("BigNum", null).apply { + mComponentName = ComponentName("com.android.systemui.clocks.bignum", "BigNumClock") + } var changeCallCount = 0 var listChangeCallCount = 0 @@ -356,12 +402,12 @@ class ClockRegistryTest : SysuiTestCase() { assertEquals(1, changeCallCount) assertEquals(0, listChangeCallCount) - assertEquals(false, pluginListener.onPluginAttached(mockPluginLifecycle1)) + assertEquals(false, pluginListener.onPluginAttached(lifecycle1)) scheduler.runCurrent() assertEquals(1, changeCallCount) assertEquals(1, listChangeCallCount) - assertEquals(false, pluginListener.onPluginAttached(mockPluginLifecycle2)) + assertEquals(false, pluginListener.onPluginAttached(lifecycle2)) scheduler.runCurrent() assertEquals(1, changeCallCount) assertEquals(2, listChangeCallCount) @@ -369,18 +415,14 @@ class ClockRegistryTest : SysuiTestCase() { @Test fun pluginAddRemove_concurrentModification() { - val mockPluginLifecycle1 = mock<PluginLifecycleManager<ClockProviderPlugin>>() - val mockPluginLifecycle2 = mock<PluginLifecycleManager<ClockProviderPlugin>>() - val mockPluginLifecycle3 = mock<PluginLifecycleManager<ClockProviderPlugin>>() - val mockPluginLifecycle4 = mock<PluginLifecycleManager<ClockProviderPlugin>>() val plugin1 = FakeClockPlugin().addClock("clock_1", "clock 1") + val lifecycle1 = FakeLifecycle("1", plugin1) val plugin2 = FakeClockPlugin().addClock("clock_2", "clock 2") + val lifecycle2 = FakeLifecycle("2", plugin2) val plugin3 = FakeClockPlugin().addClock("clock_3", "clock 3") + val lifecycle3 = FakeLifecycle("3", plugin3) val plugin4 = FakeClockPlugin().addClock("clock_4", "clock 4") - whenever(mockPluginLifecycle1.isLoaded).thenReturn(true) - whenever(mockPluginLifecycle2.isLoaded).thenReturn(true) - whenever(mockPluginLifecycle3.isLoaded).thenReturn(true) - whenever(mockPluginLifecycle4.isLoaded).thenReturn(true) + val lifecycle4 = FakeLifecycle("4", plugin4) // Set the current clock to the final clock to load registry.applySettings(ClockSettings("clock_4", null)) @@ -390,15 +432,15 @@ class ClockRegistryTest : SysuiTestCase() { // unload other plugins. This causes ClockRegistry to modify the list of available clock // plugins while it is being iterated over. In production this happens as a result of a // thread race, instead of synchronously like it does here. - whenever(mockPluginLifecycle2.unloadPlugin()).then { - pluginListener.onPluginDetached(mockPluginLifecycle1) - pluginListener.onPluginLoaded(plugin4, mockContext, mockPluginLifecycle4) + lifecycle2.onUnload = { + pluginListener.onPluginDetached(lifecycle1) + pluginListener.onPluginLoaded(plugin4, mockContext, lifecycle4) } // Load initial plugins - pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle1) - pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle2) - pluginListener.onPluginLoaded(plugin3, mockContext, mockPluginLifecycle3) + pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1) + pluginListener.onPluginLoaded(plugin2, mockContext, lifecycle2) + pluginListener.onPluginLoaded(plugin3, mockContext, lifecycle3) // Repeatedly verify the loaded providers to get final state registry.verifyLoadedProviders() @@ -484,11 +526,11 @@ class ClockRegistryTest : SysuiTestCase() { private fun testTransitClockFlag(flag: Boolean) { featureFlags.set(TRANSIT_CLOCK, flag) registry.isTransitClockEnabled = featureFlags.isEnabled(TRANSIT_CLOCK) - val mockPluginLifecycle = mock<PluginLifecycleManager<ClockProviderPlugin>>() val plugin = FakeClockPlugin() .addClock("clock_1", "clock 1") .addClock("DIGITAL_CLOCK_METRO", "metro clock") - pluginListener.onPluginLoaded(plugin, mockContext, mockPluginLifecycle) + val lifecycle = FakeLifecycle("metro", plugin) + pluginListener.onPluginLoaded(plugin, mockContext, lifecycle) val list = registry.getClocks() if (flag) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java index 1592c3007ec8..a6180ec8ea0e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java @@ -248,7 +248,7 @@ public class StatusBarIconViewTest extends SysuiTestCase { } @Test - public void testUpdateIconScale_smallerFontAndConstrainedDrawableSizeLessThanDpIconSize() { + public void testUpdateIconScale_smallerFontAndRawDrawableSizeLessThanDpIconSize() { int dpIconSize = 60; int dpDrawingSize = 30; // smaller font scaling causes the spIconSize < dpIconSize @@ -262,12 +262,42 @@ public class StatusBarIconViewTest extends SysuiTestCase { setIconDrawableWithSize(/* width= */ 50, /* height= */ 50); mIconView.maybeUpdateIconScaleDimens(); - // WHEN both the constrained drawable width/height are less than dpIconSize, + // WHEN both the raw/constrained drawable width/height are less than dpIconSize, + // THEN the icon is scaled up from constrained drawable size to the raw drawable size + float scaleToBackRawDrawableSize = (float) 50 / 40; // THEN the icon is scaled down from dpIconSize to fit the dpDrawingSize float scaleToFitDrawingSize = (float) dpDrawingSize / dpIconSize; // THEN the scaled icon should be scaled down further to fit spIconSize float scaleToFitSpIconSize = (float) spIconSize / dpIconSize; - assertEquals(scaleToFitDrawingSize * scaleToFitSpIconSize, mIconView.getIconScale(), 0.01f); + assertEquals(scaleToBackRawDrawableSize * scaleToFitDrawingSize * scaleToFitSpIconSize, + mIconView.getIconScale(), 0.01f); + } + + @Test + public void testUpdateIconScale_smallerFontAndConstrainedDrawableSizeLessThanDpIconSize() { + int dpIconSize = 60; + int dpDrawingSize = 30; + // smaller font scaling causes the spIconSize < dpIconSize + int spIconSize = 40; + // the icon view layout size would be 40x150 + // (the height is always 150 due to TEST_STATUS_BAR_HEIGHT) + setUpIconView(dpIconSize, dpDrawingSize, spIconSize); + mIconView.setNotification(mock(StatusBarNotification.class)); + // the raw drawable size is 70x70. When put the drawable into iconView whose + // layout size is 40x150, the drawable size would be constrained to 40x40 + setIconDrawableWithSize(/* width= */ 70, /* height= */ 70); + mIconView.maybeUpdateIconScaleDimens(); + + // WHEN the raw drawable width/height are larger than dpIconSize, + // but the constrained drawable width/height are less than dpIconSize, + // THEN the icon is scaled up from constrained drawable size to fit dpIconSize + float scaleToFitDpIconSize = (float) dpIconSize / 40; + // THEN the icon is scaled down from dpIconSize to fit the dpDrawingSize + float scaleToFitDrawingSize = (float) dpDrawingSize / dpIconSize; + // THEN the scaled icon should be scaled down further to fit spIconSize + float scaleToFitSpIconSize = (float) spIconSize / dpIconSize; + assertEquals(scaleToFitDpIconSize * scaleToFitDrawingSize * scaleToFitSpIconSize, + mIconView.getIconScale(), 0.01f); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt new file mode 100644 index 000000000000..8c3bfd55ecf1 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.row.wrapper + +import android.app.PendingIntent +import android.app.PendingIntent.CancelListener +import android.content.Intent +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.testing.TestableLooper.RunWithLooper +import android.testing.ViewUtils +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import androidx.test.filters.SmallTest +import com.android.internal.R +import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow +import com.android.systemui.statusbar.notification.row.NotificationTestHelper +import com.android.systemui.statusbar.notification.row.wrapper.NotificationTemplateViewWrapper.ActionPendingIntentCancellationHandler +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Mockito +import org.mockito.Mockito.times +import org.mockito.Mockito.verify + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@RunWithLooper +class NotificationTemplateViewWrapperTest : SysuiTestCase() { + + private lateinit var helper: NotificationTestHelper + + private lateinit var root: ViewGroup + private lateinit var view: ViewGroup + private lateinit var row: ExpandableNotificationRow + private lateinit var actions: ViewGroup + + private lateinit var looper: TestableLooper + + @Before + fun setUp() { + looper = TestableLooper.get(this) + allowTestableLooperAsMainThread() + helper = NotificationTestHelper(mContext, mDependency, looper) + row = helper.createRow() + // Some code in the view iterates through parents so we need some extra containers around + // it. + root = FrameLayout(mContext) + val root2 = FrameLayout(mContext) + root.addView(root2) + view = + (LayoutInflater.from(mContext) + .inflate(R.layout.notification_template_material_big_text, root2) as ViewGroup) + actions = view.findViewById(R.id.actions)!! + ViewUtils.attachView(root) + } + + @Test + fun noActionsPresent_noCrash() { + view.removeView(actions) + val wrapper = NotificationTemplateViewWrapper(mContext, view, row) + wrapper.onContentUpdated(row) + } + + @Test + fun actionPendingIntentCancelled_actionDisabled() { + val wrapper = NotificationTemplateViewWrapper(mContext, view, row) + val action1 = createActionWithPendingIntent() + val action2 = createActionWithPendingIntent() + val action3 = createActionWithPendingIntent() + wrapper.onContentUpdated(row) + waitForUiOffloadThread() // Wait for cancellation registration to execute. + + val pi3 = getPendingIntent(action3) + pi3.cancel() + looper.processAllMessages() // Wait for listener callbacks to execute + + assertThat(action1.isEnabled).isTrue() + assertThat(action2.isEnabled).isTrue() + assertThat(action3.isEnabled).isFalse() + assertThat(wrapper.mCancelledPendingIntents) + .doesNotContain(getPendingIntent(action1).hashCode()) + assertThat(wrapper.mCancelledPendingIntents) + .doesNotContain(getPendingIntent(action2).hashCode()) + assertThat(wrapper.mCancelledPendingIntents).contains(pi3.hashCode()) + } + + @Test + fun newActionWithSamePendingIntentPosted_actionDisabled() { + val wrapper = NotificationTemplateViewWrapper(mContext, view, row) + val action = createActionWithPendingIntent() + wrapper.onContentUpdated(row) + waitForUiOffloadThread() // Wait for cancellation registration to execute. + + // Cancel the intent and check action is now false. + val pi = getPendingIntent(action) + pi.cancel() + looper.processAllMessages() // Wait for listener callbacks to execute + assertThat(action.isEnabled).isFalse() + + // Create a NEW action and make sure that one will also be cancelled with same PI. + actions.removeView(action) + val newAction = createActionWithPendingIntent(pi) + wrapper.onContentUpdated(row) + looper.processAllMessages() // Wait for listener callbacks to execute + + assertThat(newAction.isEnabled).isFalse() + assertThat(wrapper.mCancelledPendingIntents).containsExactly(pi.hashCode()) + } + + @Test + fun twoActionsWithSameCancelledIntent_bothActionsDisabled() { + val wrapper = NotificationTemplateViewWrapper(mContext, view, row) + val action1 = createActionWithPendingIntent() + val action2 = createActionWithPendingIntent() + val action3 = createActionWithPendingIntent(getPendingIntent(action2)) + wrapper.onContentUpdated(row) + waitForUiOffloadThread() // Wait for cancellation registration to execute. + + val pi = getPendingIntent(action2) + pi.cancel() + looper.processAllMessages() // Wait for listener callbacks to execute + + assertThat(action1.isEnabled).isTrue() + assertThat(action2.isEnabled).isFalse() + assertThat(action3.isEnabled).isFalse() + } + + @Test + fun actionPendingIntentCancelled_whileDetached_actionDisabled() { + ViewUtils.detachView(root) + val wrapper = NotificationTemplateViewWrapper(mContext, view, row) + val action = createActionWithPendingIntent() + wrapper.onContentUpdated(row) + getPendingIntent(action).cancel() + ViewUtils.attachView(root) + waitForUiOffloadThread() + looper.processAllMessages() + + assertThat(action.isEnabled).isFalse() + } + + @Test + fun actionViewDetached_pendingIntentListenersDeregistered() { + val pi = + PendingIntent.getActivity( + mContext, + System.currentTimeMillis().toInt(), + Intent(Intent.ACTION_VIEW), + PendingIntent.FLAG_IMMUTABLE + ) + val spy = Mockito.spy(pi) + createActionWithPendingIntent(spy) + val wrapper = NotificationTemplateViewWrapper(mContext, view, row) + wrapper.onContentUpdated(row) + ViewUtils.detachView(root) + waitForUiOffloadThread() + looper.processAllMessages() + + val captor = ArgumentCaptor.forClass(CancelListener::class.java) + verify(spy, times(1)).registerCancelListener(captor.capture()) + verify(spy, times(1)).unregisterCancelListener(captor.value) + } + + @Test + fun actionViewUpdated_oldPendingIntentListenersRemoved() { + val pi = + PendingIntent.getActivity( + mContext, + System.currentTimeMillis().toInt(), + Intent(Intent.ACTION_VIEW), + PendingIntent.FLAG_IMMUTABLE + ) + val spy = Mockito.spy(pi) + val action = createActionWithPendingIntent(spy) + val wrapper = NotificationTemplateViewWrapper(mContext, view, row) + wrapper.onContentUpdated(row) + waitForUiOffloadThread() + looper.processAllMessages() + + // Grab set attach listener + val attachListener = + Mockito.spy(action.getTag(com.android.systemui.res.R.id.pending_intent_listener_tag)) + as ActionPendingIntentCancellationHandler + action.setTag(com.android.systemui.res.R.id.pending_intent_listener_tag, attachListener) + + // Update pending intent in the existing action + val newPi = + PendingIntent.getActivity( + mContext, + System.currentTimeMillis().toInt(), + Intent(Intent.ACTION_ALARM_CHANGED), + PendingIntent.FLAG_IMMUTABLE + ) + action.setTagInternal(R.id.pending_intent_tag, newPi) + wrapper.onContentUpdated(row) + waitForUiOffloadThread() + looper.processAllMessages() + + // Listeners for original pending intent need to be cleaned up now. + val captor = ArgumentCaptor.forClass(CancelListener::class.java) + verify(spy, times(1)).registerCancelListener(captor.capture()) + verify(spy, times(1)).unregisterCancelListener(captor.value) + // Attach listener has to be replaced with a new one. + assertThat(action.getTag(com.android.systemui.res.R.id.pending_intent_listener_tag)) + .isNotEqualTo(attachListener) + verify(attachListener).remove() + } + + private fun createActionWithPendingIntent(): View { + val pi = + PendingIntent.getActivity( + mContext, + System.currentTimeMillis().toInt(), + Intent(Intent.ACTION_VIEW), + PendingIntent.FLAG_IMMUTABLE + ) + return createActionWithPendingIntent(pi) + } + + private fun createActionWithPendingIntent(pi: PendingIntent): View { + val view = + LayoutInflater.from(mContext) + .inflate(R.layout.notification_material_action, null, false) + view.setTagInternal(R.id.pending_intent_tag, pi) + actions.addView(view) + return view + } + + private fun getPendingIntent(action: View): PendingIntent { + val pendingIntent = action.getTag(R.id.pending_intent_tag) as PendingIntent + assertThat(pendingIntent).isNotNull() + return pendingIntent + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java index 8e57dc1f8b2c..daf88773780e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java @@ -41,8 +41,8 @@ import static org.mockito.Mockito.when; import android.app.KeyguardManager; import android.content.res.Configuration; import android.media.AudioManager; -import android.os.Handler; import android.os.SystemClock; +import android.provider.Settings; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.Log; @@ -71,6 +71,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.FakeConfigurationController; +import com.android.systemui.util.settings.FakeSettings; import org.junit.After; import org.junit.Before; @@ -135,6 +136,8 @@ public class VolumeDialogImplTest extends SysuiTestCase { private FakeFeatureFlags mFeatureFlags; private int mLongestHideShowAnimationDuration = 250; + private FakeSettings mSecureSettings; + @Rule public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule(); @@ -147,10 +150,6 @@ public class VolumeDialogImplTest extends SysuiTestCase { mTestableLooper = TestableLooper.get(this); allowTestableLooperAsMainThread(); - // Ensure previous tests have not left messages on main looper - Handler localHandler = new Handler(mTestableLooper.getLooper()); - localHandler.removeCallbacksAndMessages(null); - when(mPostureController.getDevicePosture()) .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED); @@ -167,6 +166,8 @@ public class VolumeDialogImplTest extends SysuiTestCase { mFeatureFlags = new FakeFeatureFlags(); + mSecureSettings = new FakeSettings(); + mDialog = new VolumeDialogImpl( getContext(), mVolumeDialogController, @@ -182,7 +183,8 @@ public class VolumeDialogImplTest extends SysuiTestCase { mPostureController, mTestableLooper.getLooper(), mDumpManager, - mFeatureFlags); + mFeatureFlags, + mSecureSettings); mDialog.init(0, null); State state = createShellState(); mDialog.onStateChangedH(state); @@ -247,6 +249,18 @@ public class VolumeDialogImplTest extends SysuiTestCase { } @Test + public void testSetTimeoutValue_ComputeTimeout() { + mSecureSettings.putInt(Settings.Secure.VOLUME_DIALOG_DISMISS_TIMEOUT, 7000); + Mockito.reset(mAccessibilityMgr); + mDialog.init(0, null); + mDialog.rescheduleTimeoutH(); + verify(mAccessibilityMgr).getRecommendedTimeoutMillis( + 7000, + AccessibilityManager.FLAG_CONTENT_CONTROLS); + } + + + @Test public void testComputeTimeout_tooltip() { Mockito.reset(mAccessibilityMgr); mDialog.showCaptionsTooltip(); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSFactory.kt index bf26e719433d..cbf4ae5e3014 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSFactory.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSFactory.kt @@ -21,6 +21,6 @@ import com.android.systemui.plugins.qs.QSTile class FakeQSFactory(private val tileCreator: (String) -> QSTile?) : QSFactory { override fun createTile(tileSpec: String): QSTile? { - return tileCreator(tileSpec) + return tileCreator(tileSpec)?.also { it.tileSpec = tileSpec } } } diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java index b56b47f9c727..9dd0dca47f0e 100644 --- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java +++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java @@ -121,7 +121,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController @NonNull @GuardedBy("mGenericWindowPolicyControllerLock") - final ArraySet<Integer> mRunningUids = new ArraySet<>(); + private final ArraySet<Integer> mRunningUids = new ArraySet<>(); @Nullable private final ActivityListener mActivityListener; @Nullable private final PipBlockedCallback mPipBlockedCallback; @Nullable private final IntentListenerCallback mIntentListenerCallback; diff --git a/services/core/java/com/android/server/connectivity/OWNERS b/services/core/java/com/android/server/connectivity/OWNERS index 62c5737a2e8e..c24680e9b06a 100644 --- a/services/core/java/com/android/server/connectivity/OWNERS +++ b/services/core/java/com/android/server/connectivity/OWNERS @@ -1,2 +1,2 @@ set noparent -file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking +file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java index debf828abf0a..99a5398aa7ee 100644 --- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java +++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java @@ -33,7 +33,6 @@ import android.util.Spline; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.display.BrightnessSynchronizer; -import com.android.internal.display.BrightnessUtils; import com.android.internal.util.Preconditions; import com.android.server.display.utils.Plog; import com.android.server.display.whitebalance.DisplayWhiteBalanceController; diff --git a/core/java/com/android/internal/display/BrightnessUtils.java b/services/core/java/com/android/server/display/BrightnessUtils.java index 82b506bed80b..84fa0cccbd10 100644 --- a/core/java/com/android/internal/display/BrightnessUtils.java +++ b/services/core/java/com/android/server/display/BrightnessUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 The Android Open Source Project + * Copyright (C) 2022 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.display; +package com.android.server.display; import android.util.MathUtils; diff --git a/services/core/java/com/android/server/display/RampAnimator.java b/services/core/java/com/android/server/display/RampAnimator.java index e38c2c58f453..5ba042c51a45 100644 --- a/services/core/java/com/android/server/display/RampAnimator.java +++ b/services/core/java/com/android/server/display/RampAnimator.java @@ -20,8 +20,6 @@ import android.animation.ValueAnimator; import android.util.FloatProperty; import android.view.Choreographer; -import com.android.internal.display.BrightnessUtils; - /** * A custom animator that progressively updates a property value at * a given variable rate until it reaches a particular target value. diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java index 41053e908a00..68848a2ad426 100644 --- a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java +++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java @@ -16,35 +16,65 @@ package com.android.server.grammaticalinflection; +import static android.app.Flags.systemTermsOfAddressEnabled; import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED; import android.annotation.Nullable; +import android.app.GrammaticalInflectionManager; import android.app.IGrammaticalInflectionManager; import android.content.Context; import android.content.pm.PackageManagerInternal; import android.os.Binder; -import android.os.IBinder; +import android.os.Environment; import android.os.Process; +import android.os.ResultReceiver; +import android.os.ShellCallback; import android.os.SystemProperties; +import android.util.AtomicFile; import android.util.Log; +import android.util.SparseIntArray; +import android.util.Xml; import com.android.internal.util.FrameworkStatsLog; +import com.android.internal.util.XmlUtils; +import com.android.modules.utils.TypedXmlPullParser; +import com.android.modules.utils.TypedXmlSerializer; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.wm.ActivityTaskManagerInternal; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + /** * The implementation of IGrammaticalInflectionManager.aidl. * * <p>This service is API entry point for storing app-specific grammatical inflection. */ public class GrammaticalInflectionService extends SystemService { - private final String TAG = "GrammaticalInflection"; + private static final String TAG = "GrammaticalInflection"; + private static final String ATTR_NAME = "grammatical_gender"; + private static final String USER_SETTINGS_FILE_NAME = "user_settings.xml"; + private static final String TAG_GRAMMATICAL_INFLECTION = "grammatical_inflection"; + private static final String GRAMMATICAL_INFLECTION_ENABLED = + "i18n.grammatical_Inflection.enabled"; + private final GrammaticalInflectionBackupHelper mBackupHelper; private final ActivityTaskManagerInternal mActivityTaskManagerInternal; + private final Object mLock = new Object(); + private final SparseIntArray mGrammaticalGenderCache = new SparseIntArray(); + private PackageManagerInternal mPackageManagerInternal; - private static final String GRAMMATICAL_INFLECTION_ENABLED = - "i18n.grammatical_Inflection.enabled"; + private GrammaticalInflectionService.GrammaticalInflectionBinderService mBinderService; /** * Initializes the system service. @@ -62,22 +92,46 @@ public class GrammaticalInflectionService extends SystemService { mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mBackupHelper = new GrammaticalInflectionBackupHelper( this, context.getPackageManager()); + mBinderService = new GrammaticalInflectionBinderService(); } @Override public void onStart() { - publishBinderService(Context.GRAMMATICAL_INFLECTION_SERVICE, mService); + publishBinderService(Context.GRAMMATICAL_INFLECTION_SERVICE, mBinderService); LocalServices.addService(GrammaticalInflectionManagerInternal.class, new GrammaticalInflectionManagerInternalImpl()); } - private final IBinder mService = new IGrammaticalInflectionManager.Stub() { + private final class GrammaticalInflectionBinderService extends + IGrammaticalInflectionManager.Stub { @Override public void setRequestedApplicationGrammaticalGender( String appPackageName, int userId, int gender) { GrammaticalInflectionService.this.setRequestedApplicationGrammaticalGender( appPackageName, userId, gender); } + + @Override + public void setSystemWideGrammaticalGender(int userId, int grammaticalGender) { + checkCallerIsSystem(); + checkSystemTermsOfAddressIsEnabled(); + GrammaticalInflectionService.this.setSystemWideGrammaticalGender(grammaticalGender, + userId); + } + + @Override + public int getSystemGrammaticalGender(int userId) { + checkSystemTermsOfAddressIsEnabled(); + return GrammaticalInflectionService.this.getSystemGrammaticalGender(userId); + } + + @Override + public void onShellCommand(FileDescriptor in, FileDescriptor out, + FileDescriptor err, String[] args, ShellCallback callback, + ResultReceiver resultReceiver) { + (new GrammaticalInflectionShellCommand(mBinderService)) + .exec(this, in, out, err, args, callback, resultReceiver); + } }; private final class GrammaticalInflectionManagerInternalImpl @@ -94,12 +148,6 @@ public class GrammaticalInflectionService extends SystemService { public void stageAndApplyRestoredPayload(byte[] payload, int userId) { mBackupHelper.stageAndApplyRestoredPayload(payload, userId); } - - private void checkCallerIsSystem() { - if (Binder.getCallingUid() != Process.SYSTEM_UID) { - throw new SecurityException("Caller is not system."); - } - } } protected int getApplicationGrammaticalGender(String appPackageName, int userId) { @@ -137,4 +185,105 @@ public class GrammaticalInflectionService extends SystemService { updater.setGrammaticalGender(gender).commit(); } + + protected void setSystemWideGrammaticalGender(int grammaticalGender, int userId) { + if (!GrammaticalInflectionManager.VALID_GRAMMATICAL_GENDER_VALUES.contains( + grammaticalGender)) { + throw new IllegalArgumentException("Unknown grammatical gender"); + } + + synchronized (mLock) { + final File file = getGrammaticalGenderFile(userId); + final AtomicFile atomicFile = new AtomicFile(file); + FileOutputStream stream = null; + try { + stream = atomicFile.startWrite(); + stream.write(toXmlByteArray(grammaticalGender, stream)); + atomicFile.finishWrite(stream); + mGrammaticalGenderCache.put(userId, grammaticalGender); + } catch (IOException e) { + Log.e(TAG, "Failed to write file " + atomicFile, e); + if (stream != null) { + atomicFile.failWrite(stream); + } + throw new RuntimeException(e); + } + } + } + + // TODO(b/298591009): Add a new AppOp value for the apps that want to access the grammatical + // gender. + public int getSystemGrammaticalGender(int userId) { + synchronized (mLock) { + final File file = getGrammaticalGenderFile(userId); + if (!file.exists()) { + Log.d(TAG, "User " + userId + "doesn't have the grammatical gender file."); + return GRAMMATICAL_GENDER_NOT_SPECIFIED; + } + + if (mGrammaticalGenderCache.indexOfKey(userId) < 0) { + try { + InputStream in = new FileInputStream(file); + final TypedXmlPullParser parser = Xml.resolvePullParser(in); + mGrammaticalGenderCache.put(userId, getGrammaticalGenderFromXml(parser)); + } catch (IOException | XmlPullParserException e) { + Log.e(TAG, "Failed to parse XML configuration from " + file, e); + } + } + return mGrammaticalGenderCache.get(userId); + } + } + + private File getGrammaticalGenderFile(int userId) { + final File dir = new File(Environment.getDataSystemCeDirectory(userId), + TAG_GRAMMATICAL_INFLECTION); + return new File(dir, USER_SETTINGS_FILE_NAME); + } + + private byte[] toXmlByteArray(int grammaticalGender, FileOutputStream fileStream) { + + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + TypedXmlSerializer out = Xml.resolveSerializer(fileStream); + out.setOutput(outputStream, StandardCharsets.UTF_8.name()); + out.startDocument(/* encoding= */ null, /* standalone= */ true); + out.startTag(null, TAG_GRAMMATICAL_INFLECTION); + out.attributeInt(null, ATTR_NAME, grammaticalGender); + out.endTag(null, TAG_GRAMMATICAL_INFLECTION); + out.endDocument(); + + return outputStream.toByteArray(); + } catch (IOException e) { + return null; + } + } + + private int getGrammaticalGenderFromXml(TypedXmlPullParser parser) + throws IOException, XmlPullParserException { + + XmlUtils.nextElement(parser); + while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { + String tagName = parser.getName(); + if (TAG_GRAMMATICAL_INFLECTION.equals(tagName)) { + return parser.getAttributeInt(null, ATTR_NAME); + } else { + XmlUtils.nextElement(parser); + } + } + + return GRAMMATICAL_GENDER_NOT_SPECIFIED; + } + + private void checkCallerIsSystem() { + int callingUid = Binder.getCallingUid(); + if (callingUid != Process.SYSTEM_UID && callingUid != Process.SHELL_UID) { + throw new SecurityException("Caller is not system and shell."); + } + } + + private void checkSystemTermsOfAddressIsEnabled() { + if (!systemTermsOfAddressEnabled()) { + throw new RuntimeException("The flag must be enabled to allow calling the API."); + } + } } diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionShellCommand.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionShellCommand.java new file mode 100644 index 000000000000..d22372860ead --- /dev/null +++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionShellCommand.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.grammaticalinflection; + +import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED; + +import android.app.ActivityManager; +import android.app.GrammaticalInflectionManager; +import android.app.IGrammaticalInflectionManager; +import android.content.res.Configuration; +import android.os.RemoteException; +import android.os.ShellCommand; +import android.os.UserHandle; +import android.util.SparseArray; + +import java.io.PrintWriter; + +/** + * Shell commands for {@link GrammaticalInflectionService} + */ +class GrammaticalInflectionShellCommand extends ShellCommand { + + private static final SparseArray<String> GRAMMATICAL_GENDER_MAP = new SparseArray<>(); + static { + GRAMMATICAL_GENDER_MAP.put(Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED, + "Not specified (0)"); + GRAMMATICAL_GENDER_MAP.put(Configuration.GRAMMATICAL_GENDER_NEUTRAL, "Neuter (1)"); + GRAMMATICAL_GENDER_MAP.put(Configuration.GRAMMATICAL_GENDER_FEMININE, "Feminine (2)"); + GRAMMATICAL_GENDER_MAP.put(Configuration.GRAMMATICAL_GENDER_MASCULINE, "Masculine (3)"); + } + + private final IGrammaticalInflectionManager mBinderService; + + GrammaticalInflectionShellCommand(IGrammaticalInflectionManager grammaticalInflectionManager) { + mBinderService = grammaticalInflectionManager; + } + + @Override + public int onCommand(String cmd) { + if (cmd == null) { + return handleDefaultCommands(cmd); + } + switch (cmd) { + case "set-system-grammatical-gender": + return runSetSystemWideGrammaticalGender(); + case "get-system-grammatical-gender": + return runGetSystemGrammaticalGender(); + default: { + return handleDefaultCommands(cmd); + } + } + } + + @Override + public void onHelp() { + PrintWriter pw = getOutPrintWriter(); + pw.println("Grammatical inflection manager (grammatical_inflection) shell commands:"); + pw.println(" help"); + pw.println(" Print this help text."); + pw.println( + " set-system-grammatical-gender [--user <USER_ID>] [--grammaticalGender " + + "<GRAMMATICAL_GENDER>]"); + pw.println(" Set the system grammatical gender for system."); + pw.println(" --user <USER_ID>: apply for the given user, " + + "the current user is used when unspecified."); + pw.println( + " --grammaticalGender <GRAMMATICAL_GENDER>: The terms of address the user " + + "preferred in system, not specified (0) is used when unspecified."); + pw.println( + " eg. 0 = not_specified, 1 = neuter, 2 = feminine, 3 = masculine" + + "."); + pw.println( + " get-system-grammatical-gender [--user <USER_ID>]"); + pw.println(" Get the system grammatical gender for system."); + pw.println(" --user <USER_ID>: apply for the given user, " + + "the current user is used when unspecified."); + } + + private int runSetSystemWideGrammaticalGender() { + int userId = ActivityManager.getCurrentUser(); + int grammaticalGender = GRAMMATICAL_GENDER_NOT_SPECIFIED; + do { + String option = getNextOption(); + if (option == null) { + break; + } + switch (option) { + case "--user": { + userId = UserHandle.parseUserArg(getNextArgRequired()); + break; + } + case "-g": + case "--grammaticalGender": { + grammaticalGender = parseGrammaticalGender(); + break; + } + default: { + throw new IllegalArgumentException("Unknown option: " + option); + } + } + } while (true); + + try { + mBinderService.setSystemWideGrammaticalGender(userId, grammaticalGender); + } catch (RemoteException e) { + getOutPrintWriter().println("Remote Exception: " + e); + } + return 0; + } + + private int runGetSystemGrammaticalGender() { + int userId = ActivityManager.getCurrentUser(); + do { + String option = getNextOption(); + if (option == null) { + break; + } + switch (option) { + case "--user": { + userId = UserHandle.parseUserArg(getNextArgRequired()); + break; + } + default: { + throw new IllegalArgumentException("Unknown option: " + option); + } + } + } while (true); + + try { + int grammaticalGender = mBinderService.getSystemGrammaticalGender(userId); + getOutPrintWriter().println(GRAMMATICAL_GENDER_MAP.get(grammaticalGender)); + } catch (RemoteException e) { + getOutPrintWriter().println("Remote Exception: " + e); + } + return 0; + } + + private int parseGrammaticalGender() { + String arg = getNextArg(); + if (arg == null) { + return GRAMMATICAL_GENDER_NOT_SPECIFIED; + } else { + int grammaticalGender = Integer.parseInt(arg); + if (GrammaticalInflectionManager.VALID_GRAMMATICAL_GENDER_VALUES.contains( + grammaticalGender)) { + return grammaticalGender; + } else { + return GRAMMATICAL_GENDER_NOT_SPECIFIED; + } + } + } +} diff --git a/services/core/java/com/android/server/grammaticalinflection/OWNERS b/services/core/java/com/android/server/grammaticalinflection/OWNERS index 5f16ba9123b7..41d079ed9e75 100644 --- a/services/core/java/com/android/server/grammaticalinflection/OWNERS +++ b/services/core/java/com/android/server/grammaticalinflection/OWNERS @@ -2,3 +2,4 @@ allenwtsu@google.com goldmanj@google.com calvinpan@google.com +zoeychen@google.com diff --git a/services/core/java/com/android/server/net/OWNERS b/services/core/java/com/android/server/net/OWNERS index 9c96d46f15b8..d0e95dd55b6c 100644 --- a/services/core/java/com/android/server/net/OWNERS +++ b/services/core/java/com/android/server/net/OWNERS @@ -1,5 +1,5 @@ set noparent -file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking +file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking jsharkey@android.com sudheersai@google.com diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING index 04d1da61f3cc..390c45b6a524 100644 --- a/services/core/java/com/android/server/pm/TEST_MAPPING +++ b/services/core/java/com/android/server/pm/TEST_MAPPING @@ -145,6 +145,19 @@ "include-filter": "android.content.pm.cts.PackageManagerShellCommandMultiUserTest" } ] + }, + { + "file_patterns": [ + "(/|^)InstallPackageHelper\\.java", + "services/core/java/com/android/server/pm/parsing/.*", + "services/core/java/com/android/server/pm/pkg/parsing/.*" + ], + "name": "SdkSandboxManagerServiceUnitTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] } ], "imports": [ diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index dfc9b8b030f2..097656cac7f7 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -198,7 +198,6 @@ import com.android.internal.accessibility.util.AccessibilityStatsLogUtils; import com.android.internal.accessibility.util.AccessibilityUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.AssistUtils; -import com.android.internal.display.BrightnessUtils; import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; @@ -218,6 +217,7 @@ import com.android.server.GestureLauncherService; import com.android.server.LocalServices; import com.android.server.SystemServiceManager; import com.android.server.UiThread; +import com.android.server.display.BrightnessUtils; import com.android.server.input.InputManagerInternal; import com.android.server.input.KeyboardMetricsCollector; import com.android.server.input.KeyboardMetricsCollector.KeyboardLogEvent; diff --git a/services/core/java/com/android/server/security/rkp/OWNERS b/services/core/java/com/android/server/security/rkp/OWNERS index 348f94048311..ea6dc727c7b2 100644 --- a/services/core/java/com/android/server/security/rkp/OWNERS +++ b/services/core/java/com/android/server/security/rkp/OWNERS @@ -1 +1 @@ -file:platform/frameworks/base:master:/core/java/android/security/rkp/OWNERS +file:platform/frameworks/base:main:/core/java/android/security/rkp/OWNERS diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index a0c78702fec5..ed10346d8495 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -580,7 +580,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A IBinder mRequestedLaunchingTaskFragmentToken; // Tracking splash screen status from previous activity - boolean mAllowIconSplashScreen = true; + boolean mSplashScreenStyleSolidColor = false; boolean mPauseSchedulePendingForPip = false; @@ -2408,7 +2408,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @VisibleForTesting boolean addStartingWindow(String pkg, int resolvedTheme, ActivityRecord from, boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, - boolean activityCreated, boolean allowIcon, boolean activityAllDrawn) { + boolean activityCreated, boolean isSimple, + boolean activityAllDrawn) { // If the display is frozen, we won't do anything until the actual window is // displayed so there is no reason to put in the starting window. if (!okToDisplay()) { @@ -2443,8 +2444,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final int typeParameter = StartingSurfaceController .makeStartingWindowTypeParameter(newTask, taskSwitch, processRunning, - allowTaskSnapshot, activityCreated, allowIcon, useLegacy, - activityAllDrawn, type, packageName, mUserId); + allowTaskSnapshot, activityCreated, isSimple, useLegacy, activityAllDrawn, + type, packageName, mUserId); if (type == STARTING_WINDOW_TYPE_SNAPSHOT) { if (isActivityTypeHome()) { @@ -5365,7 +5366,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Finish should only ever commit visibility=false, so we can check full containment // rather than just direct membership. inFinishingTransition = mTransitionController.inFinishingTransition(this); - if (!inFinishingTransition && !mDisplayContent.isSleeping()) { + if (!inFinishingTransition && (visible || !mDisplayContent.isSleeping())) { Slog.e(TAG, "setVisibility=" + visible + " while transition is not collecting or finishing " + this + " caller=" + Debug.getCallers(8)); @@ -6746,7 +6747,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A void onFirstWindowDrawn(WindowState win) { firstWindowDrawn = true; // stop tracking - mAllowIconSplashScreen = false; + mSplashScreenStyleSolidColor = true; if (mStartingWindow != null) { ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Finish starting %s" @@ -6795,7 +6796,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A void onStartingWindowDrawn() { boolean wasTaskVisible = false; if (task != null) { - mAllowIconSplashScreen = false; + mSplashScreenStyleSolidColor = true; wasTaskVisible = !setTaskHasBeenVisible(); } @@ -7320,32 +7321,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } /** - * Checks whether an icon splash screen can be used in the starting window based on the - * preference in the {@code options} and this activity's theme, giving higher priority to the - * {@code options}'s preference. - * - * When no preference is specified, a default behaviour is defined: - * - if the activity is started from the home or shell app, an icon can be used - * - if the activity is started from SystemUI, an icon should not be used - * - if there is a launching activity, use its preference - * - if none of the above is met, only use an icon when the activity is started for the first - * time from a System app - * - * The returned value is sent to WmShell, which will make the final decision on what splash - * screen type will be used. - * - * @return true if an icon can be used in the splash screen - * false when an icon should not be used in the splash screen + * @return true if a solid color splash screen must be used + * false when an icon splash screen can be used, but the final decision for whether to + * use an icon or solid color splash screen will be made by WmShell. */ - private boolean canUseIconSplashScreen(ActivityRecord sourceRecord, + private boolean shouldUseSolidColorSplashScreen(ActivityRecord sourceRecord, boolean startActivity, ActivityOptions options, int resolvedTheme) { if (sourceRecord == null && !startActivity) { - // Shouldn't use an icon if this activity is not top activity. This could happen when - // adding a splash screen window to the warm start activity which is re-create because - // top is finishing. + // Use simple style if this activity is not top activity. This could happen when adding + // a splash screen window to the warm start activity which is re-create because top is + // finishing. final ActivityRecord above = task.getActivityAbove(this); if (above != null) { - return false; + return true; } } @@ -7353,33 +7341,32 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final int optionsStyle = options != null ? options.getSplashScreenStyle() : SplashScreen.SPLASH_SCREEN_STYLE_UNDEFINED; if (optionsStyle == SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR) { - return false; + return true; } else if (optionsStyle == SplashScreen.SPLASH_SCREEN_STYLE_ICON || isIconStylePreferred(resolvedTheme)) { - return true; + return false; } // Choose the default behavior when neither the ActivityRecord nor the activity theme have // specified a splash screen style. if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME || launchedFromUid == Process.SHELL_UID) { - return true; - } else if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEMUI) { return false; + } else if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEMUI) { + return true; } else { - // Need to check sourceRecord in case this activity is launched from a service or a - // trampoline activity. + // Need to check sourceRecord in case this activity is launched from a service. if (sourceRecord == null) { sourceRecord = searchCandidateLaunchingActivity(); } if (sourceRecord != null) { - return sourceRecord.mAllowIconSplashScreen; + return sourceRecord.mSplashScreenStyleSolidColor; } // Use an icon if the activity was launched from System for the first start. - // Otherwise, can't use an icon splash screen. - return mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEM && startActivity; + // Otherwise, must use solid color splash screen. + return mLaunchSourceType != LAUNCH_SOURCE_TYPE_SYSTEM || !startActivity; } } @@ -7443,7 +7430,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final int resolvedTheme = evaluateStartingWindowTheme(prev, packageName, theme, splashScreenTheme); - mAllowIconSplashScreen = canUseIconSplashScreen(sourceRecord, startActivity, + mSplashScreenStyleSolidColor = shouldUseSolidColorSplashScreen(sourceRecord, startActivity, startOptions, resolvedTheme); final boolean activityCreated = @@ -7455,7 +7442,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final boolean scheduled = addStartingWindow(packageName, resolvedTheme, prev, newTask || newSingleActivity, taskSwitch, processRunning, - allowTaskSnapshot(), activityCreated, mAllowIconSplashScreen, allDrawn); + allowTaskSnapshot(), activityCreated, mSplashScreenStyleSolidColor, allDrawn); if (DEBUG_STARTING_WINDOW_VERBOSE && scheduled) { Slog.d(TAG, "Scheduled starting window for " + this); } diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index 184de58c8446..442269ab4015 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -64,6 +64,7 @@ import android.graphics.Bitmap; import android.os.Environment; import android.os.IBinder; import android.os.RemoteException; +import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.text.TextUtils; @@ -506,6 +507,16 @@ class RecentTasks { Slog.i(TAG, "Loading recents for user " + userId + " into memory."); List<Task> tasks = mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks); + + // Tasks are ordered from most recent to least recent. Update the last active time to be + // in sync with task recency when device reboots, so the most recent task has the + // highest last active time + long currentElapsedTime = SystemClock.elapsedRealtime(); + for (int i = 0; i < tasks.size(); i++) { + Task task = tasks.get(i); + task.lastActiveTime = currentElapsedTime - i; + } + mTasks.addAll(tasks); cleanupLocked(userId); mUsersWithRecentsLoaded.put(userId, true); diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java index a0517bebca6d..a55c232990cf 100644 --- a/services/core/java/com/android/server/wm/StartingSurfaceController.java +++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java @@ -19,12 +19,12 @@ package com.android.server.wm; import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED; import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_DRAWN; import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_HANDLE_SOLID_COLOR_SCREEN; -import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_ICON; import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT; import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK; import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING; import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH; +import static android.window.StartingWindowInfo.TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN; import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_TYPE_SNAPSHOT; import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_TYPE_SPLASH_SCREEN; @@ -102,7 +102,7 @@ public class StartingSurfaceController { static int makeStartingWindowTypeParameter(boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, - boolean allowIcon, boolean useLegacy, boolean activityDrawn, int startingWindowType, + boolean isSolidColor, boolean useLegacy, boolean activityDrawn, int startingWindowType, String packageName, int userId) { int parameter = 0; if (newTask) { @@ -120,8 +120,8 @@ public class StartingSurfaceController { if (activityCreated || startingWindowType == STARTING_WINDOW_TYPE_SNAPSHOT) { parameter |= TYPE_PARAMETER_ACTIVITY_CREATED; } - if (allowIcon) { - parameter |= TYPE_PARAMETER_ALLOW_ICON; + if (isSolidColor) { + parameter |= TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN; } if (useLegacy) { parameter |= TYPE_PARAMETER_LEGACY_SPLASH_SCREEN; diff --git a/services/net/OWNERS b/services/net/OWNERS index 62c5737a2e8e..c24680e9b06a 100644 --- a/services/net/OWNERS +++ b/services/net/OWNERS @@ -1,2 +1,2 @@ set noparent -file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking +file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt index 823ce4555ca8..05477197b991 100644 --- a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt +++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt @@ -112,4 +112,4 @@ class AppIdPermissionPolicyPermissionResetTest : BaseAppIdPermissionPolicyTest() @JvmStatic fun data(): Array<Action> = Action.values() } -}
\ No newline at end of file +} diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionStatesTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionStatesTest.kt index f085bd7fd7f0..c44b2c50258e 100644 --- a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionStatesTest.kt +++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionStatesTest.kt @@ -43,8 +43,7 @@ class AppIdPermissionPolicyPermissionStatesTest : BaseAppIdPermissionPolicyTest( @Parameterized.Parameter(0) lateinit var action: Action @Before - override fun setUp() { - super.setUp() + fun setUp() { if (action == Action.ON_USER_ADDED) { createUserState(USER_ID_NEW) } @@ -881,4 +880,4 @@ class AppIdPermissionPolicyPermissionStatesTest : BaseAppIdPermissionPolicyTest( @JvmStatic fun data(): Array<Action> = Action.values() } -}
\ No newline at end of file +} diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt new file mode 100644 index 000000000000..e4e336845fca --- /dev/null +++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt @@ -0,0 +1,430 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.permission.test + +import android.content.pm.PermissionGroupInfo +import android.content.pm.PermissionInfo +import com.android.server.permission.access.GetStateScope +import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports +import com.android.server.permission.access.permission.AppIdPermissionPolicy +import com.android.server.permission.access.permission.Permission +import com.android.server.permission.access.permission.PermissionFlags +import com.android.server.testutils.mock +import com.google.common.truth.Truth.assertThat +import com.google.common.truth.Truth.assertWithMessage +import org.junit.Test +import org.mockito.Mockito.times +import org.mockito.Mockito.verify + +class AppIdPermissionPolicyTest : BaseAppIdPermissionPolicyTest() { + @Test + fun testOnAppIdRemoved_appIdIsRemoved_permissionFlagsCleared() { + val parsedPermission = mockParsedPermission(PERMISSION_NAME_0, PACKAGE_NAME_0) + val permissionOwnerPackageState = mockPackageState( + APP_ID_0, + mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(parsedPermission)) + ) + val requestingPackageState = mockPackageState( + APP_ID_1, + mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_0)) + ) + addPackageState(permissionOwnerPackageState) + addPackageState(requestingPackageState) + addPermission(parsedPermission) + setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0, PermissionFlags.INSTALL_GRANTED) + + mutateState { + with(appIdPermissionPolicy) { + onAppIdRemoved(APP_ID_1) + } + } + + val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0) + val expectedNewFlags = 0 + assertWithMessage( + "After onAppIdRemoved() is called for appId $APP_ID_1 that requests a permission" + + " owns by appId $APP_ID_0 with existing permission flags. The actual permission" + + " flags $actualFlags should be null" + ) + .that(actualFlags) + .isEqualTo(expectedNewFlags) + } + + @Test + fun testOnStorageVolumeMounted_nonSystemAppAfterNonSystemUpdate_remainsRevoked() { + val permissionOwnerPackageState = mockPackageState(APP_ID_0, mockSimpleAndroidPackage()) + val installedPackageState = mockPackageState( + APP_ID_1, + mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_0)) + ) + addPackageState(permissionOwnerPackageState) + addPackageState(installedPackageState) + addPermission(defaultPermission) + val oldFlags = PermissionFlags.INSTALL_REVOKED + setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0, oldFlags) + + mutateState { + with(appIdPermissionPolicy) { + onStorageVolumeMounted(null, listOf(installedPackageState.packageName), false) + } + } + + val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0) + val expectedNewFlags = oldFlags + assertWithMessage( + "After onStorageVolumeMounted() is called for a non-system app that requests a normal" + + " permission with existing INSTALL_REVOKED flag after a non-system-update" + + " (such as an OTA update), the actual permission flags should remain revoked." + + " The actual permission flags $actualFlags should match the expected flags" + + " $expectedNewFlags" + ) + .that(actualFlags) + .isEqualTo(expectedNewFlags) + } + + @Test + fun testOnPackageRemoved_packageIsRemoved_permissionDefinitionsAndStatesAreUpdated() { + val permissionOwnerPackageState = mockPackageState( + APP_ID_0, + mockAndroidPackage( + PACKAGE_NAME_0, + requestedPermissions = setOf(PERMISSION_NAME_0), + permissions = listOf(defaultPermission) + ) + ) + val requestingPackageState = mockPackageState( + APP_ID_1, + mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_0)) + ) + addPackageState(permissionOwnerPackageState) + addPackageState(requestingPackageState) + addPermission(defaultPermission) + val oldFlags = PermissionFlags.INSTALL_GRANTED + setPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_NAME_0, oldFlags) + setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0, oldFlags) + + mutateState { + removePackageState(permissionOwnerPackageState) + with(appIdPermissionPolicy) { + onPackageRemoved(PACKAGE_NAME_0, APP_ID_0) + } + } + + assertWithMessage( + "After onPackageRemoved() is called for a permission owner, the permission" + + " definitions owned by this package should be removed" + ) + .that(getPermission(PERMISSION_NAME_0)) + .isNull() + + val app0ActualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_NAME_0) + val app0ExpectedNewFlags = 0 + assertWithMessage( + "After onPackageRemoved() is called for a permission owner, the permission states of" + + " this app should be trimmed. The actual permission flags $app0ActualFlags should" + + " match the expected flags $app0ExpectedNewFlags" + ) + .that(app0ActualFlags) + .isEqualTo(app0ExpectedNewFlags) + + val app1ActualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0) + val app1ExpectedNewFlags = PermissionFlags.INSTALL_REVOKED + assertWithMessage( + "After onPackageRemoved() is called for a permission owner, the permission states of" + + " the permission requester should remain unchanged. The actual permission flags" + + " $app1ActualFlags should match the expected flags $app1ExpectedNewFlags" + ) + .that(app1ActualFlags) + .isEqualTo(app1ExpectedNewFlags) + } + + @Test + fun testOnPackageInstalled_nonSystemAppIsInstalled_upgradeExemptFlagIsCleared() { + val oldFlags = PermissionFlags.SOFT_RESTRICTED or PermissionFlags.UPGRADE_EXEMPT + testOnPackageInstalled( + oldFlags, + permissionInfoFlags = PermissionInfo.FLAG_SOFT_RESTRICTED + ) {} + val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0) + val expectedNewFlags = PermissionFlags.SOFT_RESTRICTED + assertWithMessage( + "After onPackageInstalled() is called for a non-system app that requests a runtime" + + " soft restricted permission, UPGRADE_EXEMPT flag should be removed. The actual" + + " permission flags $actualFlags should match the expected flags $expectedNewFlags" + ) + .that(actualFlags) + .isEqualTo(expectedNewFlags) + } + + @Test + fun testOnPackageInstalled_systemAppIsInstalled_upgradeExemptFlagIsRetained() { + val oldFlags = PermissionFlags.SOFT_RESTRICTED or PermissionFlags.UPGRADE_EXEMPT + testOnPackageInstalled( + oldFlags, + permissionInfoFlags = PermissionInfo.FLAG_SOFT_RESTRICTED, + isInstalledPackageSystem = true + ) {} + val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0) + val expectedNewFlags = oldFlags + assertWithMessage( + "After onPackageInstalled() is called for a system app that requests a runtime" + + " soft restricted permission, UPGRADE_EXEMPT flag should be retained. The actual" + + " permission flags $actualFlags should match the expected flags $expectedNewFlags" + ) + .that(actualFlags) + .isEqualTo(expectedNewFlags) + } + + @Test + fun testOnPackageInstalled_requestedPermissionAlsoRequestedBySystemApp_exemptFlagIsRetained() { + val oldFlags = PermissionFlags.SOFT_RESTRICTED or PermissionFlags.UPGRADE_EXEMPT + testOnPackageInstalled( + oldFlags, + permissionInfoFlags = PermissionInfo.FLAG_SOFT_RESTRICTED + ) { + val systemAppPackageState = mockPackageState( + APP_ID_1, + mockAndroidPackage(PACKAGE_NAME_2, requestedPermissions = setOf(PERMISSION_NAME_0)), + isSystem = true + ) + addPackageState(systemAppPackageState) + } + val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0) + val expectedNewFlags = oldFlags + assertWithMessage( + "After onPackageInstalled() is called for a non-system app that requests a runtime" + + " soft restricted permission, and that permission is also requested by a system" + + " app in the same appId, UPGRADE_EXEMPT flag should be retained. The actual" + + " permission flags $actualFlags should match the expected flags $expectedNewFlags" + ) + .that(actualFlags) + .isEqualTo(expectedNewFlags) + } + + @Test + fun testOnPackageInstalled_restrictedPermissionsNotExempt_getsRestrictionFlags() { + val oldFlags = PermissionFlags.RESTRICTION_REVOKED + testOnPackageInstalled( + oldFlags, + permissionInfoFlags = PermissionInfo.FLAG_HARD_RESTRICTED + ) {} + val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0) + val expectedNewFlags = oldFlags + assertWithMessage( + "After onPackageInstalled() is called for a non-system app that requests a runtime" + + " hard restricted permission that is not exempted. The actual permission flags" + + " $actualFlags should match the expected flags $expectedNewFlags" + ) + .that(actualFlags) + .isEqualTo(expectedNewFlags) + } + + @Test + fun testOnPackageInstalled_restrictedPermissionsIsExempted_clearsRestrictionFlags() { + val oldFlags = PermissionFlags.SOFT_RESTRICTED or PermissionFlags.INSTALLER_EXEMPT + testOnPackageInstalled( + oldFlags, + permissionInfoFlags = PermissionInfo.FLAG_SOFT_RESTRICTED + ) {} + val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0) + val expectedNewFlags = PermissionFlags.INSTALLER_EXEMPT + assertWithMessage( + "After onPackageInstalled() is called for a non-system app that requests a runtime" + + " soft restricted permission that is exempted. The actual permission flags" + + " $actualFlags should match the expected flags $expectedNewFlags" + ) + .that(actualFlags) + .isEqualTo(expectedNewFlags) + } + + private fun testOnPackageInstalled( + oldFlags: Int, + permissionInfoFlags: Int = 0, + isInstalledPackageSystem: Boolean = false, + additionalSetup: () -> Unit + ) { + val parsedPermission = mockParsedPermission( + PERMISSION_NAME_0, + PACKAGE_NAME_0, + protectionLevel = PermissionInfo.PROTECTION_DANGEROUS, + flags = permissionInfoFlags + ) + val permissionOwnerPackageState = mockPackageState( + APP_ID_0, + mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(parsedPermission)) + ) + addPackageState(permissionOwnerPackageState) + addPermission(parsedPermission) + + additionalSetup() + + mutateState { + val installedPackageState = mockPackageState( + APP_ID_1, + mockAndroidPackage( + PACKAGE_NAME_1, + requestedPermissions = setOf(PERMISSION_NAME_0), + ), + isSystem = isInstalledPackageSystem, + ) + addPackageState(installedPackageState, newState) + setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0, oldFlags, newState) + with(appIdPermissionPolicy) { + onPackageInstalled(installedPackageState, USER_ID_0) + } + } + } + + @Test + fun testOnStateMutated_notEmpty_isCalledForEachListener() { + val mockListener = mock<AppIdPermissionPolicy.OnPermissionFlagsChangedListener> {} + appIdPermissionPolicy.addOnPermissionFlagsChangedListener(mockListener) + + GetStateScope(oldState).apply { + with(appIdPermissionPolicy) { + onStateMutated() + } + } + + verify(mockListener, times(1)).onStateMutated() + } + + @Test + fun testGetPermissionTrees() { + val permissionTrees: IndexedMap<String, Permission> + GetStateScope(oldState).apply { + with(appIdPermissionPolicy) { + permissionTrees = getPermissionTrees() + } + } + + assertThat(oldState.systemState.permissionTrees).isEqualTo(permissionTrees) + } + + @Test + fun testFindPermissionTree() { + val permissionTree = createSimplePermission(isTree = true) + val actualPermissionTree: Permission? + oldState.mutateSystemState().mutatePermissionTrees()[PERMISSION_TREE_NAME] = permissionTree + + GetStateScope(oldState).apply { + with(appIdPermissionPolicy) { + actualPermissionTree = findPermissionTree(PERMISSION_BELONGS_TO_A_TREE) + } + } + + assertThat(actualPermissionTree).isEqualTo(permissionTree) + } + + @Test + fun testAddPermissionTree() { + val permissionTree = createSimplePermission(isTree = true) + + mutateState { + with(appIdPermissionPolicy) { + addPermissionTree(permissionTree) + } + } + + assertThat(newState.systemState.permissionTrees[PERMISSION_TREE_NAME]) + .isEqualTo(permissionTree) + } + + @Test + fun testGetPermissionGroups() { + val permissionGroups: IndexedMap<String, PermissionGroupInfo> + GetStateScope(oldState).apply { + with(appIdPermissionPolicy) { + permissionGroups = getPermissionGroups() + } + } + + assertThat(oldState.systemState.permissionGroups).isEqualTo(permissionGroups) + } + + @Test + fun testGetPermissions() { + val permissions: IndexedMap<String, Permission> + GetStateScope(oldState).apply { + with(appIdPermissionPolicy) { + permissions = getPermissions() + } + } + + assertThat(oldState.systemState.permissions).isEqualTo(permissions) + } + + @Test + fun testAddPermission() { + val permission = createSimplePermission() + + mutateState { + with(appIdPermissionPolicy) { + addPermission(permission) + } + } + + assertThat(newState.systemState.permissions[PERMISSION_NAME_0]).isEqualTo(permission) + } + + @Test + fun testRemovePermission() { + val permission = createSimplePermission() + + mutateState { + with(appIdPermissionPolicy) { + addPermission(permission) + removePermission(permission) + } + } + + assertThat(newState.systemState.permissions[PERMISSION_NAME_0]).isNull() + } + + @Test + fun testGetUidPermissionFlags() { + val uidPermissionFlags: IndexedMap<String, Int>? + GetStateScope(oldState).apply { + with(appIdPermissionPolicy) { + uidPermissionFlags = getUidPermissionFlags(APP_ID_0, USER_ID_0) + } + } + + assertThat(oldState.userStates[USER_ID_0]!!.appIdPermissionFlags[APP_ID_0]) + .isEqualTo(uidPermissionFlags) + } + + @Test + fun testUpdateAndGetPermissionFlags() { + val flags = PermissionFlags.INSTALL_GRANTED + var actualFlags = 0 + mutateState { + with(appIdPermissionPolicy) { + updatePermissionFlags( + APP_ID_0, + USER_ID_0, + PERMISSION_NAME_0, + PermissionFlags.MASK_ALL, + flags + ) + actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_NAME_0) + } + } + + assertThat(actualFlags).isEqualTo(flags) + } +} diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/BaseAppIdPermissionPolicyTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/BaseAppIdPermissionPolicyTest.kt index 7966c5c4d961..ec84bc329674 100644 --- a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/BaseAppIdPermissionPolicyTest.kt +++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/BaseAppIdPermissionPolicyTest.kt @@ -34,7 +34,6 @@ import com.android.server.permission.access.MutateStateScope import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports import com.android.server.permission.access.permission.AppIdPermissionPolicy import com.android.server.permission.access.permission.Permission -import com.android.server.permission.access.permission.PermissionFlags import com.android.server.permission.access.util.hasBits import com.android.server.pm.parsing.PackageInfoUtils import com.android.server.pm.pkg.AndroidPackage @@ -45,10 +44,8 @@ import com.android.server.pm.pkg.component.ParsedPermissionGroup import com.android.server.testutils.any import com.android.server.testutils.mock import com.android.server.testutils.whenever -import com.google.common.truth.Truth.assertWithMessage import org.junit.Before import org.junit.Rule -import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyLong @@ -56,7 +53,7 @@ import org.mockito.ArgumentMatchers.anyLong * Mocking unit test for AppIdPermissionPolicy. */ @RunWith(AndroidJUnit4::class) -open class BaseAppIdPermissionPolicyTest { +abstract class BaseAppIdPermissionPolicyTest { protected lateinit var oldState: MutableAccessState protected lateinit var newState: MutableAccessState @@ -80,7 +77,7 @@ open class BaseAppIdPermissionPolicyTest { .build() @Before - open fun setUp() { + fun baseSetUp() { oldState = MutableAccessState() createUserState(USER_ID_0) oldState.mutateExternalState().setPackageStates(ArrayMap()) @@ -139,78 +136,6 @@ open class BaseAppIdPermissionPolicyTest { } } - @Test - fun testOnAppIdRemoved_appIdIsRemoved_permissionFlagsCleared() { - val parsedPermission = mockParsedPermission(PERMISSION_NAME_0, PACKAGE_NAME_0) - val permissionOwnerPackageState = mockPackageState( - APP_ID_0, - mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(parsedPermission)) - ) - val requestingPackageState = mockPackageState( - APP_ID_1, - mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_0)) - ) - addPackageState(permissionOwnerPackageState) - addPackageState(requestingPackageState) - addPermission(parsedPermission) - setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0, PermissionFlags.INSTALL_GRANTED) - - mutateState { - with(appIdPermissionPolicy) { - onAppIdRemoved(APP_ID_1) - } - } - - val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0) - val expectedNewFlags = 0 - assertWithMessage( - "After onAppIdRemoved() is called for appId $APP_ID_1 that requests a permission" + - " owns by appId $APP_ID_0 with existing permission flags. The actual permission" + - " flags $actualFlags should be null" - ) - .that(actualFlags) - .isEqualTo(expectedNewFlags) - } - - @Test - fun testOnPackageRemoved_packageIsRemoved_permissionsAreTrimmedAndStatesAreEvaluated() { - // TODO - // shouldn't reuse test cases because it's really different despite it's also for - // trim permission states. It's different because it's package removal - } - - @Test - fun testOnPackageInstalled_nonSystemAppIsInstalled_upgradeExemptFlagIsCleared() { - // TODO - // should be fine for it to be its own test cases and not to re-use - // clearRestrictedPermissionImplicitExemption - } - - @Test - fun testOnPackageInstalled_systemAppIsInstalled_upgradeExemptFlagIsRetained() { - // TODO - } - - @Test - fun testOnPackageInstalled_requestedPermissionAlsoRequestedBySystemApp_exemptFlagIsRetained() { - // TODO - } - - @Test - fun testOnPackageInstalled_restrictedPermissionsNotExempt_getsRestrictionFlags() { - // TODO - } - - @Test - fun testOnPackageInstalled_restrictedPermissionsIsExempted_clearsRestrictionFlags() { - // TODO - } - - @Test - fun testOnStateMutated_notEmpty_isCalledForEachListener() { - // TODO - } - /** * Mock an AndroidPackage with PACKAGE_NAME_0, PERMISSION_NAME_0 and PERMISSION_GROUP_NAME_0 */ @@ -221,6 +146,15 @@ open class BaseAppIdPermissionPolicyTest { permissions = listOf(defaultPermissionTree, defaultPermission) ) + protected fun createSimplePermission(isTree: Boolean = false): Permission { + val parsedPermission = if (isTree) { defaultPermissionTree } else { defaultPermission } + val permissionInfo = PackageInfoUtils.generatePermissionInfo( + parsedPermission, + PackageManager.GET_META_DATA.toLong() + )!! + return Permission(permissionInfo, true, Permission.TYPE_MANIFEST, APP_ID_0) + } + protected inline fun mutateState(action: MutateStateScope.() -> Unit) { newState = oldState.toMutable() MutateStateScope(oldState, newState).action() @@ -330,15 +264,26 @@ open class BaseAppIdPermissionPolicyTest { ) { state.mutateExternalState().apply { setPackageStates( - packageStates.toMutableMap().apply { - put(packageState.packageName, packageState) - } + packageStates.toMutableMap().apply { put(packageState.packageName, packageState) } ) mutateAppIdPackageNames().mutateOrPut(packageState.appId) { MutableIndexedListSet() } .add(packageState.packageName) } } + protected fun removePackageState( + packageState: PackageState, + state: MutableAccessState = oldState + ) { + state.mutateExternalState().apply { + setPackageStates( + packageStates.toMutableMap().apply { remove(packageState.packageName) } + ) + mutateAppIdPackageNames().mutateOrPut(packageState.appId) { MutableIndexedListSet() } + .remove(packageState.packageName) + } + } + protected fun addDisabledSystemPackageState( packageState: PackageState, state: MutableAccessState = oldState @@ -429,6 +374,7 @@ open class BaseAppIdPermissionPolicyTest { @JvmStatic protected val PERMISSION_NAME_0 = "permissionName0" @JvmStatic protected val PERMISSION_NAME_1 = "permissionName1" @JvmStatic protected val PERMISSION_NAME_2 = "permissionName2" + @JvmStatic protected val PERMISSION_BELONGS_TO_A_TREE = "permissionTree.permission" @JvmStatic protected val PERMISSION_READ_EXTERNAL_STORAGE = Manifest.permission.READ_EXTERNAL_STORAGE @JvmStatic protected val PERMISSION_POST_NOTIFICATIONS = diff --git a/services/tests/RemoteProvisioningServiceTests/OWNERS b/services/tests/RemoteProvisioningServiceTests/OWNERS index 348f94048311..ea6dc727c7b2 100644 --- a/services/tests/RemoteProvisioningServiceTests/OWNERS +++ b/services/tests/RemoteProvisioningServiceTests/OWNERS @@ -1 +1 @@ -file:platform/frameworks/base:master:/core/java/android/security/rkp/OWNERS +file:platform/frameworks/base:main:/core/java/android/security/rkp/OWNERS diff --git a/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java b/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java index 7a4327cc0598..2fd6e5fb6892 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java @@ -19,7 +19,6 @@ package com.android.server.display; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.isA; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -28,18 +27,15 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.ContextWrapper; import android.database.ContentObserver; -import android.hardware.display.BrightnessInfo; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.net.Uri; import android.os.Handler; -import android.os.PowerManager; import android.os.UserHandle; import android.os.test.TestLooper; import android.provider.Settings; import android.test.mock.MockContentResolver; import android.view.Display; -import android.view.DisplayAdjustments; import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.SmallTest; @@ -63,7 +59,6 @@ public class BrightnessSynchronizerTest { private static final float EPSILON = 0.00001f; private static final Uri BRIGHTNESS_URI = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS); - private static final float BRIGHTNESS_MAX = 0.6f; private Context mContext; private MockContentResolver mContentResolverSpy; @@ -71,7 +66,6 @@ public class BrightnessSynchronizerTest { private DisplayListener mDisplayListener; private ContentObserver mContentObserver; private TestLooper mTestLooper; - private BrightnessSynchronizer mSynchronizer; @Mock private DisplayManager mDisplayManagerMock; @Captor private ArgumentCaptor<DisplayListener> mDisplayListenerCaptor; @@ -80,17 +74,7 @@ public class BrightnessSynchronizerTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - - Display display = mock(Display.class); - when(display.getDisplayAdjustments()).thenReturn(new DisplayAdjustments()); - BrightnessInfo info = new BrightnessInfo(PowerManager.BRIGHTNESS_INVALID_FLOAT, - PowerManager.BRIGHTNESS_MIN, BRIGHTNESS_MAX, - BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, BRIGHTNESS_MAX, - BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE); - when(display.getBrightnessInfo()).thenReturn(info); - - mContext = spy(new ContextWrapper( - ApplicationProvider.getApplicationContext().createDisplayContext(display))); + mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext())); mContentResolverSpy = spy(new MockContentResolver(mContext)); mContentResolverSpy.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); when(mContext.getContentResolver()).thenReturn(mContentResolverSpy); @@ -144,12 +128,13 @@ public class BrightnessSynchronizerTest { @Test public void testSetSameIntValue_nothingUpdated() { putFloatSetting(0.5f); + putIntSetting(128); start(); - putIntSetting(fToI(0.5f)); + putIntSetting(128); advanceTime(10); verify(mDisplayManagerMock, times(0)).setBrightness( - eq(Display.DEFAULT_DISPLAY), eq(0.5f)); + eq(Display.DEFAULT_DISPLAY), eq(iToF(128))); } @Test @@ -169,13 +154,14 @@ public class BrightnessSynchronizerTest { // Verify that this update did not get sent to float, because synchronizer // is still waiting for confirmation of its first value. verify(mDisplayManagerMock, times(0)).setBrightness( - Display.DEFAULT_DISPLAY, iToF(20)); + eq(Display.DEFAULT_DISPLAY), eq(iToF(20))); // Send the confirmation of the initial change. This should trigger the new value to // finally be processed and we can verify that the new value (20) is sent. putIntSetting(fToI(0.4f)); advanceTime(10); - verify(mDisplayManagerMock).setBrightness(Display.DEFAULT_DISPLAY, iToF(20)); + verify(mDisplayManagerMock).setBrightness( + eq(Display.DEFAULT_DISPLAY), eq(iToF(20))); } @@ -197,7 +183,8 @@ public class BrightnessSynchronizerTest { advanceTime(200); // Verify that the new value gets sent because the timeout expired. - verify(mDisplayManagerMock).setBrightness(Display.DEFAULT_DISPLAY, iToF(20)); + verify(mDisplayManagerMock).setBrightness( + eq(Display.DEFAULT_DISPLAY), eq(iToF(20))); // Send a confirmation of the initial event, BrightnessSynchronizer should treat this as a // new event because the timeout had already expired @@ -209,14 +196,14 @@ public class BrightnessSynchronizerTest { // Verify we sent what would have been the confirmation as a new event to displaymanager. // We do both fToI and iToF because the conversions are not symmetric. - verify(mDisplayManagerMock).setBrightness(Display.DEFAULT_DISPLAY, - iToF(fToI(0.4f))); + verify(mDisplayManagerMock).setBrightness( + eq(Display.DEFAULT_DISPLAY), eq(iToF(fToI(0.4f)))); } - private void start() { - mSynchronizer = new BrightnessSynchronizer(mContext, mTestLooper.getLooper(), + private BrightnessSynchronizer start() { + BrightnessSynchronizer bs = new BrightnessSynchronizer(mContext, mTestLooper.getLooper(), mClock::now); - mSynchronizer.startSynchronizing(); + bs.startSynchronizing(); verify(mDisplayManagerMock).registerDisplayListener(mDisplayListenerCaptor.capture(), isA(Handler.class), eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS)); mDisplayListener = mDisplayListenerCaptor.getValue(); @@ -224,6 +211,7 @@ public class BrightnessSynchronizerTest { verify(mContentResolverSpy).registerContentObserver(eq(BRIGHTNESS_URI), eq(false), mContentObserverCaptor.capture(), eq(UserHandle.USER_ALL)); mContentObserver = mContentObserverCaptor.getValue(); + return bs; } private int getIntSetting() throws Exception { @@ -253,11 +241,11 @@ public class BrightnessSynchronizerTest { } private int fToI(float brightness) { - return mSynchronizer.brightnessFloatToIntSetting(brightness); + return BrightnessSynchronizer.brightnessFloatToInt(brightness); } private float iToF(int brightness) { - return mSynchronizer.brightnessIntSettingToFloat(brightness); + return BrightnessSynchronizer.brightnessIntToFloat(brightness); } private void advanceTime(long timeMs) { diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java index 306de525e53c..2396905aecbf 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -71,7 +71,6 @@ import android.graphics.Rect; import android.hardware.Sensor; import android.hardware.SensorManager; import android.hardware.display.BrightnessConfiguration; -import android.hardware.display.BrightnessInfo; import android.hardware.display.Curve; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerGlobal; @@ -95,7 +94,6 @@ import android.os.Process; import android.os.RemoteException; import android.view.ContentRecordingSession; import android.view.Display; -import android.view.DisplayAdjustments; import android.view.DisplayCutout; import android.view.DisplayEventReceiver; import android.view.DisplayInfo; @@ -103,6 +101,7 @@ import android.view.Surface; import android.view.SurfaceControl; import android.window.DisplayWindowPolicyController; +import androidx.test.InstrumentationRegistry; import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; @@ -333,11 +332,7 @@ public class DisplayManagerServiceTest { LocalServices.removeServiceForTest(UserManagerInternal.class); LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal); // TODO: b/287945043 - Display display = mock(Display.class); - when(display.getDisplayAdjustments()).thenReturn(new DisplayAdjustments()); - when(display.getBrightnessInfo()).thenReturn(mock(BrightnessInfo.class)); - mContext = spy(new ContextWrapper( - ApplicationProvider.getApplicationContext().createDisplayContext(display))); + mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext())); mResources = Mockito.spy(mContext.getResources()); manageDisplaysPermission(/* granted= */ false); when(mContext.getResources()).thenReturn(mResources); @@ -1912,6 +1907,7 @@ public class DisplayManagerServiceTest { @Test public void testSettingTwoBrightnessConfigurationsOnMultiDisplay() { + Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); // get the first two internal displays diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java new file mode 100644 index 000000000000..a7c8a6cee0d9 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java @@ -0,0 +1,890 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.companion.virtual; + +import static android.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES; +import static android.view.WindowManager.LayoutParams.FLAG_SECURE; +import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.WindowConfiguration; +import android.companion.virtual.IVirtualDeviceIntentInterceptor; +import android.companion.virtual.VirtualDeviceManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.net.Uri; +import android.os.RemoteException; +import android.os.UserHandle; +import android.platform.test.annotations.Presubmit; +import android.platform.test.flag.junit.SetFlagsRule; +import android.util.ArraySet; +import android.view.Display; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.internal.app.BlockedAppStreamingActivity; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +@Presubmit +@RunWith(AndroidJUnit4.class) +public class GenericWindowPolicyControllerTest { + + private static final int DISPLAY_ID = Display.DEFAULT_DISPLAY + 1; + private static final int TEST_UID = 1234567; + private static final String DISPLAY_CATEGORY = "com.display.category"; + private static final String NONBLOCKED_APP_PACKAGE_NAME = "com.someapp"; + private static final String BLOCKED_PACKAGE_NAME = "com.blockedapp"; + private static final int FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES = 0x00000; + private static final String TEST_SITE = "http://test"; + private static final ComponentName BLOCKED_APP_STREAMING_COMPONENT = + new ComponentName("android", BlockedAppStreamingActivity.class.getName()); + private static final ComponentName BLOCKED_COMPONENT = new ComponentName(BLOCKED_PACKAGE_NAME, + BLOCKED_PACKAGE_NAME); + private static final ComponentName NONBLOCKED_COMPONENT = new ComponentName( + NONBLOCKED_APP_PACKAGE_NAME, NONBLOCKED_APP_PACKAGE_NAME); + + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + @Mock + private GenericWindowPolicyController.PipBlockedCallback mPipBlockedCallback; + @Mock + private VirtualDeviceManager.ActivityListener mActivityListener; + @Mock + private GenericWindowPolicyController.IntentListenerCallback mIntentListenerCallback; + @Mock + private GenericWindowPolicyController.ActivityBlockedCallback mActivityBlockedCallback; + @Mock + private GenericWindowPolicyController.RunningAppsChangedListener mRunningAppsChangedListener; + @Mock + private GenericWindowPolicyController.SecureWindowCallback mSecureWindowCallback; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + } + + @Test + public void showTasksInHostDeviceRecents() { + GenericWindowPolicyController gwpc = createGwpc(); + + gwpc.setShowInHostDeviceRecents(true); + assertThat(gwpc.canShowTasksInHostDeviceRecents()).isTrue(); + + gwpc.setShowInHostDeviceRecents(false); + assertThat(gwpc.canShowTasksInHostDeviceRecents()).isFalse(); + } + + @Test + public void containsUid() { + GenericWindowPolicyController gwpc = createGwpc(); + + assertThat(gwpc.containsUid(TEST_UID)).isFalse(); + + gwpc.onRunningAppsChanged(new ArraySet<>(Arrays.asList(TEST_UID))); + assertThat(gwpc.containsUid(TEST_UID)).isTrue(); + + gwpc.onRunningAppsChanged(new ArraySet<>()); + assertThat(gwpc.containsUid(TEST_UID)).isFalse(); + } + + @Test + public void isEnteringPipAllowed_falseByDefault() { + GenericWindowPolicyController gwpc = createGwpc(); + + assertThat(gwpc.isEnteringPipAllowed(TEST_UID)).isFalse(); + verify(mPipBlockedCallback).onEnteringPipBlocked(TEST_UID); + } + + @Test + public void isEnteringPipAllowed_dpcSupportsPinned_allowed() { + GenericWindowPolicyController gwpc = createGwpc(); + gwpc.setSupportedWindowingModes(new HashSet<>( + Arrays.asList(WindowConfiguration.WINDOWING_MODE_FULLSCREEN, + WindowConfiguration.WINDOWING_MODE_PINNED))); + assertThat(gwpc.isEnteringPipAllowed(TEST_UID)).isTrue(); + verify(mPipBlockedCallback, never()).onEnteringPipBlocked(TEST_UID); + } + + @Test + public void openNonBlockedAppOnVirtualDisplay_isNotBlocked() { + GenericWindowPolicyController gwpc = createGwpc(); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + NONBLOCKED_APP_PACKAGE_NAME, + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + assertActivityCanBeLaunched(gwpc, activityInfo); + } + + @Test + public void activityDoesNotSupportDisplayOnRemoteDevices_isBlocked() { + GenericWindowPolicyController gwpc = createGwpc(); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + NONBLOCKED_APP_PACKAGE_NAME, + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoteDevices */ false, + /* targetDisplayCategory */ null); + assertActivityIsBlocked(gwpc, activityInfo); + } + + @Test + public void openBlockedComponentOnVirtualDisplay_isBlocked() { + GenericWindowPolicyController gwpc = createGwpcWithBlockedComponent(BLOCKED_COMPONENT); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + BLOCKED_PACKAGE_NAME, + BLOCKED_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + assertActivityIsBlocked(gwpc, activityInfo); + } + + @Test + public void addActivityPolicyExemption_openBlockedOnVirtualDisplay_isBlocked() { + GenericWindowPolicyController gwpc = createGwpc(); + gwpc.setDisplayId(DISPLAY_ID); + gwpc.setActivityLaunchDefaultAllowed(true); + gwpc.addActivityPolicyExemption(BLOCKED_COMPONENT); + + ActivityInfo activityInfo = getActivityInfo( + BLOCKED_PACKAGE_NAME, + BLOCKED_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + assertActivityIsBlocked(gwpc, activityInfo); + } + + @Test + public void openNotAllowedComponentOnBlocklistVirtualDisplay_isBlocked() { + GenericWindowPolicyController gwpc = createGwpcWithAllowedComponent(NONBLOCKED_COMPONENT); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + BLOCKED_PACKAGE_NAME, + BLOCKED_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + assertActivityIsBlocked(gwpc, activityInfo); + } + + @Test + public void addActivityPolicyExemption_openNotAllowedOnVirtualDisplay_isBlocked() { + GenericWindowPolicyController gwpc = createGwpc(); + gwpc.setDisplayId(DISPLAY_ID); + gwpc.setActivityLaunchDefaultAllowed(false); + gwpc.addActivityPolicyExemption(NONBLOCKED_COMPONENT); + + ActivityInfo activityInfo = getActivityInfo( + BLOCKED_PACKAGE_NAME, + BLOCKED_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + assertActivityIsBlocked(gwpc, activityInfo); + } + + @Test + public void openAllowedComponentOnBlocklistVirtualDisplay_startsActivity() { + GenericWindowPolicyController gwpc = createGwpcWithAllowedComponent(NONBLOCKED_COMPONENT); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + NONBLOCKED_APP_PACKAGE_NAME, + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + assertActivityCanBeLaunched(gwpc, activityInfo); + } + + @Test + public void addActivityPolicyExemption_openAllowedOnVirtualDisplay_startsActivity() { + GenericWindowPolicyController gwpc = createGwpc(); + gwpc.setDisplayId(DISPLAY_ID); + gwpc.setActivityLaunchDefaultAllowed(false); + gwpc.addActivityPolicyExemption(NONBLOCKED_COMPONENT); + + ActivityInfo activityInfo = getActivityInfo( + NONBLOCKED_APP_PACKAGE_NAME, + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + assertActivityCanBeLaunched(gwpc, activityInfo); + } + + @Test + public void canActivityBeLaunched_mismatchingUserHandle_isBlocked() { + GenericWindowPolicyController gwpc = createGwpc(); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + NONBLOCKED_APP_PACKAGE_NAME, + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null, + /* uid */ UserHandle.PER_USER_RANGE + 1); + assertActivityIsBlocked(gwpc, activityInfo); + } + + @Test + public void canActivityBeLaunched_blockedAppStreamingComponent_isNeverBlocked() { + GenericWindowPolicyController gwpc = createGwpc(); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + BLOCKED_APP_STREAMING_COMPONENT.getPackageName(), + BLOCKED_APP_STREAMING_COMPONENT.getClassName(), + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + assertActivityCanBeLaunched(gwpc, activityInfo); + } + + @Test + public void canActivityBeLaunched_blockedAppStreamingComponentExplicitlyBlocked_isNeverBlocked() { + GenericWindowPolicyController gwpc = createGwpcWithBlockedComponent( + BLOCKED_APP_STREAMING_COMPONENT); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + BLOCKED_APP_STREAMING_COMPONENT.getPackageName(), + BLOCKED_APP_STREAMING_COMPONENT.getClassName(), + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + + assertActivityCanBeLaunched(gwpc, activityInfo); + } + + @Test + public void canActivityBeLaunched_blockedAppStreamingComponentExemptFromStreaming_isNeverBlocked() { + GenericWindowPolicyController gwpc = createGwpc(); + gwpc.setDisplayId(DISPLAY_ID); + gwpc.setActivityLaunchDefaultAllowed(true); + gwpc.addActivityPolicyExemption(BLOCKED_APP_STREAMING_COMPONENT); + + ActivityInfo activityInfo = getActivityInfo( + BLOCKED_APP_STREAMING_COMPONENT.getPackageName(), + BLOCKED_APP_STREAMING_COMPONENT.getClassName(), + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + + assertActivityCanBeLaunched(gwpc, activityInfo); + } + + @Test + public void canActivityBeLaunched_blockedAppStreamingComponentNotAllowlisted_isNeverBlocked() { + GenericWindowPolicyController gwpc = createGwpcWithAllowedComponent(NONBLOCKED_COMPONENT); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + BLOCKED_APP_STREAMING_COMPONENT.getPackageName(), + BLOCKED_APP_STREAMING_COMPONENT.getClassName(), + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + + assertActivityCanBeLaunched(gwpc, activityInfo); + } + + @Test + public void canActivityBeLaunched_blockedAppStreamingComponentNotExemptFromBlocklist_isNeverBlocked() { + GenericWindowPolicyController gwpc = createGwpc(); + gwpc.setDisplayId(DISPLAY_ID); + gwpc.setActivityLaunchDefaultAllowed(false); + gwpc.addActivityPolicyExemption(NONBLOCKED_COMPONENT); + + ActivityInfo activityInfo = getActivityInfo( + BLOCKED_APP_STREAMING_COMPONENT.getPackageName(), + BLOCKED_APP_STREAMING_COMPONENT.getClassName(), + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + + assertActivityCanBeLaunched(gwpc, activityInfo); + } + + @Test + public void canActivityBeLaunched_customDisplayCategoryMatches_isNotBlocked() { + GenericWindowPolicyController gwpc = createGwpcWithDisplayCategory(DISPLAY_CATEGORY); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + NONBLOCKED_APP_PACKAGE_NAME, + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ DISPLAY_CATEGORY); + + assertActivityCanBeLaunched(gwpc, activityInfo); + } + + @Test + public void canActivityBeLaunched_customDisplayCategoryDoesNotMatch_isBlocked() { + GenericWindowPolicyController gwpc = createGwpcWithDisplayCategory(DISPLAY_CATEGORY); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + NONBLOCKED_APP_PACKAGE_NAME, + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ "some.random.category"); + assertActivityIsBlocked(gwpc, activityInfo); + } + + @Test + public void canActivityBeLaunched_crossTaskLaunch_fromDefaultDisplay_isNotBlocked() { + GenericWindowPolicyController gwpc = createGwpc(); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + NONBLOCKED_APP_PACKAGE_NAME, + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + assertActivityCanBeLaunched(gwpc, Display.DEFAULT_DISPLAY, true, + WindowConfiguration.WINDOWING_MODE_FULLSCREEN, activityInfo); + } + + @Test + public void canActivityBeLaunched_crossTaskLaunchFromVirtualDisplay_notExplicitlyBlocked_isNotBlocked() { + GenericWindowPolicyController gwpc = createGwpcWithCrossTaskNavigationBlockedFor( + BLOCKED_COMPONENT); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + NONBLOCKED_APP_PACKAGE_NAME, + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + + assertActivityCanBeLaunched(gwpc, DISPLAY_ID, true, + WindowConfiguration.WINDOWING_MODE_FULLSCREEN, activityInfo); + } + + @Test + public void canActivityBeLaunched_crossTaskLaunchFromVirtualDisplay_explicitlyBlocked_isBlocked() { + GenericWindowPolicyController gwpc = createGwpcWithCrossTaskNavigationBlockedFor( + BLOCKED_COMPONENT); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + BLOCKED_PACKAGE_NAME, + BLOCKED_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + assertActivityIsBlocked(gwpc, DISPLAY_ID, true, + WindowConfiguration.WINDOWING_MODE_FULLSCREEN, activityInfo); + } + + @Test + public void canActivityBeLaunched_crossTaskLaunchFromVirtualDisplay_notAllowed_isBlocked() { + GenericWindowPolicyController gwpc = createGwpcWithCrossTaskNavigationAllowed( + NONBLOCKED_COMPONENT); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + BLOCKED_PACKAGE_NAME, + BLOCKED_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + assertActivityIsBlocked(gwpc, DISPLAY_ID, true, + WindowConfiguration.WINDOWING_MODE_FULLSCREEN, activityInfo); + } + + @Test + public void canActivityBeLaunched_crossTaskLaunchFromVirtualDisplay_allowed_isNotBlocked() { + GenericWindowPolicyController gwpc = createGwpcWithCrossTaskNavigationAllowed( + NONBLOCKED_COMPONENT); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + NONBLOCKED_APP_PACKAGE_NAME, + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + assertActivityCanBeLaunched(gwpc, DISPLAY_ID, true, + WindowConfiguration.WINDOWING_MODE_FULLSCREEN, activityInfo); + } + + @Test + public void canActivityBeLaunched_unsupportedWindowingMode_isBlocked() { + GenericWindowPolicyController gwpc = createGwpc(); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + NONBLOCKED_APP_PACKAGE_NAME, + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + assertActivityIsBlocked(gwpc, DISPLAY_ID, true, WindowConfiguration.WINDOWING_MODE_PINNED, + activityInfo); + } + + @Test + public void canActivityBeLaunched_permissionComponent_isBlocked() { + GenericWindowPolicyController gwpc = createGwpcWithPermissionComponent(BLOCKED_COMPONENT); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + BLOCKED_PACKAGE_NAME, + BLOCKED_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + assertActivityIsBlocked(gwpc, activityInfo); + } + + @Test + public void registerRunningAppsChangedListener_onRunningAppsChanged_listenersNotified() { + ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(TEST_UID)); + GenericWindowPolicyController gwpc = createGwpc(); + + gwpc.registerRunningAppsChangedListener(mRunningAppsChangedListener); + gwpc.onRunningAppsChanged(uids); + + assertThat(gwpc.getRunningAppsChangedListenersSizeForTesting()).isEqualTo(1); + verify(mRunningAppsChangedListener).onRunningAppsChanged(uids); + } + + @Test + public void onRunningAppsChanged_empty_onDisplayEmpty() { + ArraySet<Integer> uids = new ArraySet<>(); + GenericWindowPolicyController gwpc = createGwpc(); + gwpc.setDisplayId(DISPLAY_ID); + + gwpc.onRunningAppsChanged(uids); + + assertThat(gwpc.getRunningAppsChangedListenersSizeForTesting()).isEqualTo(0); + verify(mActivityListener).onDisplayEmpty(DISPLAY_ID); + } + + @Test + public void noRunningAppsChangedListener_onRunningAppsChanged_doesNotThrowException() { + ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(TEST_UID)); + GenericWindowPolicyController gwpc = createGwpc(); + + gwpc.onRunningAppsChanged(uids); + + assertThat(gwpc.getRunningAppsChangedListenersSizeForTesting()).isEqualTo(0); + verify(mRunningAppsChangedListener, never()).onRunningAppsChanged(uids); + } + + @Test + public void registerUnregisterRunningAppsChangedListener_onRunningAppsChanged_doesNotThrowException() { + ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(TEST_UID)); + GenericWindowPolicyController gwpc = createGwpc(); + + gwpc.registerRunningAppsChangedListener(mRunningAppsChangedListener); + gwpc.unregisterRunningAppsChangedListener(mRunningAppsChangedListener); + gwpc.onRunningAppsChanged(uids); + + assertThat(gwpc.getRunningAppsChangedListenersSizeForTesting()).isEqualTo(0); + verify(mRunningAppsChangedListener, never()).onRunningAppsChanged(uids); + } + + @Test + public void canActivityBeLaunched_intentInterceptedWhenRegistered_activityNoLaunch() + throws RemoteException { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(TEST_SITE)); + + IVirtualDeviceIntentInterceptor.Stub interceptor = + mock(IVirtualDeviceIntentInterceptor.Stub.class); + doNothing().when(interceptor).onIntentIntercepted(any()); + doReturn(interceptor).when(interceptor).asBinder(); + doReturn(interceptor).when(interceptor).queryLocalInterface(anyString()); + + GenericWindowPolicyController gwpc = createGwpc(); + ActivityInfo activityInfo = getActivityInfo( + NONBLOCKED_APP_PACKAGE_NAME, + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + + // register interceptor and intercept intent + when(mIntentListenerCallback.shouldInterceptIntent(any(Intent.class))).thenReturn(true); + assertThat(gwpc.canActivityBeLaunched(activityInfo, intent, + WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID, /*isNewTask=*/false)) + .isFalse(); + + // unregister interceptor and launch activity + when(mIntentListenerCallback.shouldInterceptIntent(any(Intent.class))).thenReturn(false); + assertThat(gwpc.canActivityBeLaunched(activityInfo, intent, + WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID, /*isNewTask=*/false)) + .isTrue(); + } + + @Test + public void canActivityBeLaunched_noMatchIntentFilter_activityLaunches() { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("testing")); + + GenericWindowPolicyController gwpc = createGwpc(); + ActivityInfo activityInfo = getActivityInfo( + NONBLOCKED_APP_PACKAGE_NAME, + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + + // register interceptor with different filter + when(mIntentListenerCallback.shouldInterceptIntent(any(Intent.class))).thenReturn(false); + assertThat(gwpc.canActivityBeLaunched(activityInfo, intent, + WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID, /*isNewTask=*/false)) + .isTrue(); + verify(mIntentListenerCallback).shouldInterceptIntent(any(Intent.class)); + } + + @Test + public void onTopActivitychanged_null_noCallback() { + GenericWindowPolicyController gwpc = createGwpc(); + + gwpc.onTopActivityChanged(null, 0, 0); + verify(mActivityListener, never()) + .onTopActivityChanged(anyInt(), any(ComponentName.class), anyInt()); + } + + @Test + public void onTopActivitychanged_activityListenerCallbackObserved() { + int userId = 1000; + GenericWindowPolicyController gwpc = createGwpc(); + gwpc.setDisplayId(DISPLAY_ID); + + gwpc.onTopActivityChanged(BLOCKED_COMPONENT, 0, userId); + verify(mActivityListener) + .onTopActivityChanged(eq(DISPLAY_ID), eq(BLOCKED_COMPONENT), eq(userId)); + } + + @Test + public void keepActivityOnWindowFlagsChanged_noChange() { + GenericWindowPolicyController gwpc = createGwpc(); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + NONBLOCKED_APP_PACKAGE_NAME, + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + + assertThat(gwpc.keepActivityOnWindowFlagsChanged(activityInfo, 0, 0)).isTrue(); + + verify(mSecureWindowCallback, never()).onSecureWindowShown(DISPLAY_ID, + activityInfo.applicationInfo.uid); + verify(mActivityBlockedCallback, never()).onActivityBlocked(DISPLAY_ID, activityInfo); + } + + @Test + public void keepActivityOnWindowFlagsChanged_flagSecure_isAllowedAfterTM() { + GenericWindowPolicyController gwpc = createGwpc(); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + NONBLOCKED_APP_PACKAGE_NAME, + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + + assertThat(gwpc.keepActivityOnWindowFlagsChanged(activityInfo, FLAG_SECURE, 0)).isTrue(); + + verify(mSecureWindowCallback).onSecureWindowShown(DISPLAY_ID, + activityInfo.applicationInfo.uid); + verify(mActivityBlockedCallback, never()).onActivityBlocked(DISPLAY_ID, activityInfo); + } + + @Test + public void keepActivityOnWindowFlagsChanged_systemFlagHideNonSystemOverlayWindows_isAllowedAfterTM() { + GenericWindowPolicyController gwpc = createGwpc(); + gwpc.setDisplayId(DISPLAY_ID); + + ActivityInfo activityInfo = getActivityInfo( + NONBLOCKED_APP_PACKAGE_NAME, + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + + assertThat(gwpc.keepActivityOnWindowFlagsChanged(activityInfo, 0, + SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS)).isTrue(); + + verify(mSecureWindowCallback, never()).onSecureWindowShown(DISPLAY_ID, + activityInfo.applicationInfo.uid); + verify(mActivityBlockedCallback, never()).onActivityBlocked(DISPLAY_ID, activityInfo); + } + + @Test + public void getCustomHomeComponent_noneSet() { + GenericWindowPolicyController gwpc = createGwpc(); + + assertThat(gwpc.getCustomHomeComponent()).isNull(); + } + + @Test + public void getCustomHomeComponent_returnsHomeComponent() { + GenericWindowPolicyController gwpc = createGwpcWithCustomHomeComponent( + NONBLOCKED_COMPONENT); + + assertThat(gwpc.getCustomHomeComponent()).isEqualTo(NONBLOCKED_COMPONENT); + } + + private GenericWindowPolicyController createGwpc() { + return new GenericWindowPolicyController( + 0, + 0, + /* allowedUsers= */ new ArraySet<>(getCurrentUserId()), + /* activityLaunchAllowedByDefault= */ true, + /* activityPolicyExemptions= */ new ArraySet<>(), + /* crossTaskNavigationAllowedByDefault= */ true, + /* crossTaskNavigationExemptions= */ new ArraySet<>(), + /* permissionDialogComponent= */ null, + /* activityListener= */ mActivityListener, + /* pipBlockedCallback= */ mPipBlockedCallback, + /* activityBlockedCallback= */ mActivityBlockedCallback, + /* secureWindowCallback= */ mSecureWindowCallback, + /* intentListenerCallback= */ mIntentListenerCallback, + /* displayCategories= */ new ArraySet<>(), + /* showTasksInHostDeviceRecents= */ true, + /* customHomeComponent= */ null); + } + + private GenericWindowPolicyController createGwpcWithCustomHomeComponent( + ComponentName homeComponent) { + return new GenericWindowPolicyController( + 0, + 0, + /* allowedUsers= */ new ArraySet<>(getCurrentUserId()), + /* activityLaunchAllowedByDefault= */ true, + /* activityPolicyExemptions= */ new ArraySet<>(), + /* crossTaskNavigationAllowedByDefault= */ true, + /* crossTaskNavigationExemptions= */ new ArraySet<>(), + /* permissionDialogComponent= */ null, + /* activityListener= */ mActivityListener, + /* pipBlockedCallback= */ mPipBlockedCallback, + /* activityBlockedCallback= */ mActivityBlockedCallback, + /* secureWindowCallback= */ null, + /* intentListenerCallback= */ mIntentListenerCallback, + /* displayCategories= */ new ArraySet<>(), + /* showTasksInHostDeviceRecents= */ true, + /* customHomeComponent= */ homeComponent); + } + + private GenericWindowPolicyController createGwpcWithBlockedComponent( + ComponentName blockedComponent) { + return new GenericWindowPolicyController( + 0, + 0, + /* allowedUsers= */ new ArraySet<>(getCurrentUserId()), + /* activityLaunchAllowedByDefault= */ true, + /* activityPolicyExemptions= */ Collections.singleton(blockedComponent), + /* crossTaskNavigationAllowedByDefault= */ true, + /* crossTaskNavigationExemptions= */ new ArraySet<>(), + /* permissionDialogComponent= */ null, + /* activityListener= */ mActivityListener, + /* pipBlockedCallback= */ mPipBlockedCallback, + /* activityBlockedCallback= */ mActivityBlockedCallback, + /* secureWindowCallback= */ null, + /* intentListenerCallback= */ mIntentListenerCallback, + /* displayCategories= */ new ArraySet<>(), + /* showTasksInHostDeviceRecents= */ true, + /* customHomeComponent= */ null); + } + + private GenericWindowPolicyController createGwpcWithAllowedComponent( + ComponentName allowedComponent) { + return new GenericWindowPolicyController( + 0, + 0, + /* allowedUsers= */ new ArraySet<>(getCurrentUserId()), + /* activityLaunchAllowedByDefault= */ false, + /* activityPolicyExemptions= */ Collections.singleton(allowedComponent), + /* crossTaskNavigationAllowedByDefault= */ true, + /* crossTaskNavigationExemptions= */ new ArraySet<>(), + /* permissionDialogComponent= */ null, + /* activityListener= */ mActivityListener, + /* pipBlockedCallback= */ mPipBlockedCallback, + /* activityBlockedCallback= */ mActivityBlockedCallback, + /* secureWindowCallback= */ null, + /* intentListenerCallback= */ mIntentListenerCallback, + /* displayCategories= */ new ArraySet<>(), + /* showTasksInHostDeviceRecents= */ true, + /* customHomeComponent= */ null); + } + + private GenericWindowPolicyController createGwpcWithDisplayCategory( + String displayCategory) { + return new GenericWindowPolicyController( + 0, + 0, + /* allowedUsers= */ new ArraySet<>(getCurrentUserId()), + /* activityLaunchAllowedByDefault= */ true, + /* activityPolicyExemptions= */ new ArraySet<>(), + /* crossTaskNavigationAllowedByDefault= */ true, + /* crossTaskNavigationExemptions= */ new ArraySet<>(), + /* permissionDialogComponent= */ null, + /* activityListener= */ mActivityListener, + /* pipBlockedCallback= */ mPipBlockedCallback, + /* activityBlockedCallback= */ mActivityBlockedCallback, + /* secureWindowCallback= */ null, + /* intentListenerCallback= */ mIntentListenerCallback, + /* displayCategories= */ Collections.singleton(displayCategory), + /* showTasksInHostDeviceRecents= */ true, + /* customHomeComponent= */ null); + } + + private GenericWindowPolicyController createGwpcWithCrossTaskNavigationBlockedFor( + ComponentName blockedComponent) { + return new GenericWindowPolicyController( + 0, + 0, + /* allowedUsers= */ new ArraySet<>(getCurrentUserId()), + /* activityLaunchAllowedByDefault= */ true, + /* activityPolicyExemptions= */ new ArraySet<>(), + /* crossTaskNavigationAllowedByDefault= */ true, + /* crossTaskNavigationExemptions= */ Collections.singleton(blockedComponent), + /* permissionDialogComponent= */ null, + /* activityListener= */ mActivityListener, + /* pipBlockedCallback= */ mPipBlockedCallback, + /* activityBlockedCallback= */ mActivityBlockedCallback, + /* secureWindowCallback= */ null, + /* intentListenerCallback= */ mIntentListenerCallback, + /* displayCategories= */ new ArraySet<>(), + /* showTasksInHostDeviceRecents= */ true, + /* customHomeComponent= */ null); + } + + private GenericWindowPolicyController createGwpcWithCrossTaskNavigationAllowed( + ComponentName allowedComponent) { + return new GenericWindowPolicyController( + 0, + 0, + /* allowedUsers= */ new ArraySet<>(getCurrentUserId()), + /* activityLaunchAllowedByDefault= */ true, + /* activityPolicyExemptions= */ new ArraySet<>(), + /* crossTaskNavigationAllowedByDefault= */ false, + /* crossTaskNavigationExemptions= */ Collections.singleton(allowedComponent), + /* permissionDialogComponent= */ null, + /* activityListener= */ mActivityListener, + /* pipBlockedCallback= */ mPipBlockedCallback, + /* activityBlockedCallback= */ mActivityBlockedCallback, + /* secureWindowCallback= */ null, + /* intentListenerCallback= */ mIntentListenerCallback, + /* displayCategories= */ new ArraySet<>(), + /* showTasksInHostDeviceRecents= */ true, + /* customHomeComponent= */ null); + } + + private GenericWindowPolicyController createGwpcWithPermissionComponent( + ComponentName permissionComponent) { + //TODO instert the component + return new GenericWindowPolicyController( + 0, + 0, + /* allowedUsers= */ new ArraySet<>(getCurrentUserId()), + /* activityLaunchAllowedByDefault= */ true, + /* activityPolicyExemptions= */ new ArraySet<>(), + /* crossTaskNavigationAllowedByDefault= */ false, + /* crossTaskNavigationExemptions= */ new ArraySet<>(), + /* permissionDialogComponent= */ permissionComponent, + /* activityListener= */ mActivityListener, + /* pipBlockedCallback= */ mPipBlockedCallback, + /* activityBlockedCallback= */ mActivityBlockedCallback, + /* secureWindowCallback= */ null, + /* intentListenerCallback= */ mIntentListenerCallback, + /* displayCategories= */ new ArraySet<>(), + /* showTasksInHostDeviceRecents= */ true, + /* customHomeComponent= */ null); + } + + private Set<UserHandle> getCurrentUserId() { + Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + return new ArraySet<>(Arrays.asList(context.getUser())); + } + + private ActivityInfo getActivityInfo( + String packageName, String name, boolean displayOnRemoteDevices, + String requiredDisplayCategory) { + return getActivityInfo(packageName, name, displayOnRemoteDevices, requiredDisplayCategory, + 0); + } + + private ActivityInfo getActivityInfo( + String packageName, String name, boolean displayOnRemoteDevices, + String requiredDisplayCategory, int uid) { + ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.uid = uid; + + ActivityInfo activityInfo = new ActivityInfo(); + activityInfo.packageName = packageName; + activityInfo.name = name; + activityInfo.flags = displayOnRemoteDevices + ? FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES : FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES; + activityInfo.applicationInfo = applicationInfo; + activityInfo.requiredDisplayCategory = requiredDisplayCategory; + return activityInfo; + } + + private void assertActivityCanBeLaunched(GenericWindowPolicyController gwpc, + ActivityInfo activityInfo) { + assertActivityCanBeLaunched(gwpc, DISPLAY_ID, false, + WindowConfiguration.WINDOWING_MODE_FULLSCREEN, activityInfo); + } + + private void assertActivityCanBeLaunched(GenericWindowPolicyController gwpc, int fromDisplay, + boolean isNewTask, int windowingMode, ActivityInfo activityInfo) { + assertThat(gwpc.canActivityBeLaunched(activityInfo, null, windowingMode, fromDisplay, + isNewTask)).isTrue(); + + verify(mActivityBlockedCallback, never()).onActivityBlocked(fromDisplay, activityInfo); + verify(mIntentListenerCallback, never()).shouldInterceptIntent(any(Intent.class)); + } + + private void assertActivityIsBlocked(GenericWindowPolicyController gwpc, + ActivityInfo activityInfo) { + assertActivityIsBlocked(gwpc, DISPLAY_ID, false, + WindowConfiguration.WINDOWING_MODE_FULLSCREEN, activityInfo); + } + + private void assertActivityIsBlocked(GenericWindowPolicyController gwpc, int fromDisplay, + boolean isNewTask, int windowingMode, ActivityInfo activityInfo) { + assertThat(gwpc.canActivityBeLaunched(activityInfo, null, windowingMode, fromDisplay, + isNewTask)).isFalse(); + + verify(mActivityBlockedCallback).onActivityBlocked(fromDisplay, activityInfo); + verify(mIntentListenerCallback, never()).shouldInterceptIntent(any(Intent.class)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java index 1e6306cb4071..263d4701eba1 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java @@ -24,6 +24,7 @@ import static android.content.Context.DEVICE_ID_DEFAULT; import static android.content.Context.DEVICE_ID_INVALID; import static android.content.Intent.ACTION_VIEW; import static android.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES; +import static android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; @@ -70,6 +71,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.hardware.Sensor; import android.hardware.display.DisplayManagerGlobal; import android.hardware.display.DisplayManagerInternal; @@ -303,7 +305,7 @@ public class VirtualDeviceManagerServiceTest { ActivityInfo activityInfo = getActivityInfo( NONBLOCKED_APP_PACKAGE_NAME, NONBLOCKED_APP_PACKAGE_NAME, - /* displayOnRemoveDevices= */ true, + /* displayOnRemoteDevices= */ true, targetDisplayCategory); Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent( activityInfo, mAssociationInfo.getDisplayName()); @@ -314,12 +316,12 @@ public class VirtualDeviceManagerServiceTest { private ActivityInfo getActivityInfo( - String packageName, String name, boolean displayOnRemoveDevices, + String packageName, String name, boolean displayOnRemoteDevices, String requiredDisplayCategory) { ActivityInfo activityInfo = new ActivityInfo(); activityInfo.packageName = packageName; activityInfo.name = name; - activityInfo.flags = displayOnRemoveDevices + activityInfo.flags = displayOnRemoteDevices ? FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES : FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES; activityInfo.applicationInfo = mApplicationInfoMock; activityInfo.requiredDisplayCategory = requiredDisplayCategory; @@ -1427,7 +1429,7 @@ public class VirtualDeviceManagerServiceTest { ActivityInfo activityInfo = getActivityInfo( NONBLOCKED_APP_PACKAGE_NAME, NONBLOCKED_APP_PACKAGE_NAME, - /* displayOnRemoveDevices */ true, + /* displayOnRemoteDevices */ true, /* targetDisplayCategory */ null); Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent( activityInfo, mAssociationInfo.getDisplayName()); @@ -1448,7 +1450,7 @@ public class VirtualDeviceManagerServiceTest { ActivityInfo activityInfo = getActivityInfo( PERMISSION_CONTROLLER_PACKAGE_NAME, PERMISSION_CONTROLLER_PACKAGE_NAME, - /* displayOnRemoveDevices */ false, + /* displayOnRemoteDevices */ false, /* targetDisplayCategory */ null); Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent( activityInfo, mAssociationInfo.getDisplayName()); @@ -1513,7 +1515,7 @@ public class VirtualDeviceManagerServiceTest { ActivityInfo activityInfo = getActivityInfo( SETTINGS_PACKAGE_NAME, SETTINGS_PACKAGE_NAME, - /* displayOnRemoveDevices */ true, + /* displayOnRemoteDevices */ true, /* targetDisplayCategory */ null); Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent( activityInfo, mAssociationInfo.getDisplayName()); @@ -1534,7 +1536,7 @@ public class VirtualDeviceManagerServiceTest { ActivityInfo activityInfo = getActivityInfo( VENDING_PACKAGE_NAME, VENDING_PACKAGE_NAME, - /* displayOnRemoveDevices */ true, + /* displayOnRemoteDevices */ true, /* targetDisplayCategory */ null); Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent( activityInfo, mAssociationInfo.getDisplayName()); @@ -1555,7 +1557,7 @@ public class VirtualDeviceManagerServiceTest { ActivityInfo activityInfo = getActivityInfo( GOOGLE_DIALER_PACKAGE_NAME, GOOGLE_DIALER_PACKAGE_NAME, - /* displayOnRemoveDevices */ true, + /* displayOnRemoteDevices */ true, /* targetDisplayCategory */ null); Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent( activityInfo, mAssociationInfo.getDisplayName()); @@ -1576,7 +1578,7 @@ public class VirtualDeviceManagerServiceTest { ActivityInfo activityInfo = getActivityInfo( GOOGLE_MAPS_PACKAGE_NAME, GOOGLE_MAPS_PACKAGE_NAME, - /* displayOnRemoveDevices */ true, + /* displayOnRemoteDevices */ true, /* targetDisplayCategory */ null); Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent( activityInfo, mAssociationInfo.getDisplayName()); @@ -1616,6 +1618,54 @@ public class VirtualDeviceManagerServiceTest { } @Test + public void canActivityBeLaunched_permissionDialog_flagDisabled_isBlocked() { + mSetFlagsRule.disableFlags(Flags.FLAG_STREAM_PERMISSIONS); + VirtualDeviceParams params = new VirtualDeviceParams.Builder().build(); + mDeviceImpl.close(); + mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params); + doNothing().when(mContext).startActivityAsUser(any(), any(), any()); + + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest( + DISPLAY_ID_1); + ComponentName permissionComponent = getPermissionDialogComponent(); + ActivityInfo activityInfo = getActivityInfo( + permissionComponent.getPackageName(), + permissionComponent.getClassName(), + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + assertThat(gwpc.canActivityBeLaunched(activityInfo, null, + WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false)) + .isFalse(); + + Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent( + activityInfo, mAssociationInfo.getDisplayName()); + verify(mContext).startActivityAsUser(argThat(intent -> + intent.filterEquals(blockedAppIntent)), any(), any()); + } + + @Test + public void canActivityBeLaunched_permissionDialog_flagEnabled_isStreamed() { + mSetFlagsRule.enableFlags(Flags.FLAG_STREAM_PERMISSIONS); + VirtualDeviceParams params = new VirtualDeviceParams.Builder().build(); + mDeviceImpl.close(); + mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params); + + addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); + GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest( + DISPLAY_ID_1); + ComponentName permissionComponent = getPermissionDialogComponent(); + ActivityInfo activityInfo = getActivityInfo( + permissionComponent.getPackageName(), + permissionComponent.getClassName(), + /* displayOnRemoteDevices */ true, + /* targetDisplayCategory */ null); + assertThat(gwpc.canActivityBeLaunched(activityInfo, null, + WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false)) + .isTrue(); + } + + @Test public void canActivityBeLaunched_activityCanLaunch() { Intent intent = new Intent(ACTION_VIEW, Uri.parse(TEST_SITE)); addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1); @@ -1624,7 +1674,7 @@ public class VirtualDeviceManagerServiceTest { ActivityInfo activityInfo = getActivityInfo( NONBLOCKED_APP_PACKAGE_NAME, NONBLOCKED_APP_PACKAGE_NAME, - /* displayOnRemoveDevices */ true, + /* displayOnRemoteDevices */ true, /* targetDisplayCategory */ null); assertThat(gwpc.canActivityBeLaunched(activityInfo, intent, WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false)) @@ -1648,7 +1698,7 @@ public class VirtualDeviceManagerServiceTest { ActivityInfo activityInfo = getActivityInfo( NONBLOCKED_APP_PACKAGE_NAME, NONBLOCKED_APP_PACKAGE_NAME, - /* displayOnRemoveDevices */ true, + /* displayOnRemoteDevices */ true, /* targetDisplayCategory */ null); IntentFilter intentFilter = new IntentFilter(Intent.ACTION_VIEW); @@ -1691,7 +1741,7 @@ public class VirtualDeviceManagerServiceTest { ActivityInfo activityInfo = getActivityInfo( NONBLOCKED_APP_PACKAGE_NAME, NONBLOCKED_APP_PACKAGE_NAME, - /* displayOnRemoveDevices */ true, + /* displayOnRemoteDevices */ true, /* targetDisplayCategory */ null); IntentFilter intentFilter = new IntentFilter(Intent.ACTION_VIEW); @@ -1812,6 +1862,13 @@ public class VirtualDeviceManagerServiceTest { NONBLOCKED_APP_PACKAGE_NAME); } + private ComponentName getPermissionDialogComponent() { + Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS); + PackageManager packageManager = mContext.getPackageManager(); + intent.setPackage(packageManager.getPermissionControllerPackageName()); + return intent.resolveActivity(packageManager); + } + /** Helper class to drop permissions temporarily and restore them at the end of a test. */ static final class DropShellPermissionsTemporarily implements AutoCloseable { DropShellPermissionsTemporarily() { diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java index 90d9452fb9c3..07dd59d2e2d8 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java @@ -32,11 +32,12 @@ import android.companion.virtual.VirtualDevice; import android.companion.virtual.flags.Flags; import android.os.Parcel; import android.platform.test.annotations.Presubmit; -import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.SetFlagsRule; import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -51,6 +52,9 @@ public class VirtualDeviceTest { private static final String DEVICE_NAME = "VirtualDeviceName"; private static final String DISPLAY_NAME = "DisplayName"; + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Mock private IVirtualDevice mVirtualDevice; @@ -101,9 +105,10 @@ public class VirtualDeviceTest { assertThat(device.getDisplayName().toString()).isEqualTo(DISPLAY_NAME); } - @RequiresFlagsEnabled(Flags.FLAG_VDM_PUBLIC_APIS) @Test public void virtualDevice_getDisplayIds() throws Exception { + mSetFlagsRule.enableFlags(Flags.FLAG_VDM_PUBLIC_APIS); + VirtualDevice virtualDevice = new VirtualDevice( mVirtualDevice, VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null); @@ -116,9 +121,10 @@ public class VirtualDeviceTest { assertThat(virtualDevice.getDisplayIds()).isEqualTo(displayIds); } - @RequiresFlagsEnabled(Flags.FLAG_VDM_PUBLIC_APIS) @Test public void virtualDevice_hasCustomSensorSupport() throws Exception { + mSetFlagsRule.enableFlags(Flags.FLAG_VDM_PUBLIC_APIS); + VirtualDevice virtualDevice = new VirtualDevice( mVirtualDevice, VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index f65cb93258bc..40ac7b1ccdca 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -2855,14 +2855,14 @@ public class ActivityRecordTests extends WindowTestsBase { .setTask(sourceRecord.getTask()).build(); secondRecord.showStartingWindow(null /* prev */, true /* newTask */, false, true /* startActivity */, sourceRecord); - assertTrue(secondRecord.mAllowIconSplashScreen); + assertFalse(secondRecord.mSplashScreenStyleSolidColor); secondRecord.onStartingWindowDrawn(); final ActivityRecord finalRecord = new ActivityBuilder(mAtm) .setTask(sourceRecord.getTask()).build(); finalRecord.showStartingWindow(null /* prev */, true /* newTask */, false, true /* startActivity */, secondRecord); - assertFalse(finalRecord.mAllowIconSplashScreen); + assertTrue(finalRecord.mSplashScreenStyleSolidColor); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index 25619b9ec5e8..4c25a4bf1455 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -91,6 +91,7 @@ import java.util.List; import java.util.Random; import java.util.Set; import java.util.function.Function; +import java.util.stream.Collectors; /** * Build/Install/Run: @@ -563,6 +564,38 @@ public class RecentTasksTest extends WindowTestsBase { } @Test + public void testTasksWithCorrectOrderOfLastActiveTime() { + mRecentTasks.setOnlyTestVisibleRange(); + mRecentTasks.unloadUserDataFromMemoryLocked(TEST_USER_0_ID); + + // Setup some tasks for the user + mTaskPersister.mUserTaskIdsOverride = new SparseBooleanArray(); + mTaskPersister.mUserTaskIdsOverride.put(1, true); + mTaskPersister.mUserTaskIdsOverride.put(2, true); + mTaskPersister.mUserTaskIdsOverride.put(3, true); + mTaskPersister.mUserTasksOverride = new ArrayList<>(); + mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask1").build()); + mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask2").build()); + mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask3").build()); + + // Assert no user tasks are initially loaded + assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).hasLength(0); + + // Load tasks + mRecentTasks.loadUserRecentsLocked(TEST_USER_0_ID); + assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID); + + // Sort the time descendingly so the order should be in-sync with task recency (most + // recent to least recent) + List<Task> tasksSortedByTime = mRecentTasks.getRawTasks().stream() + .sorted((o1, o2) -> Long.compare(o2.lastActiveTime, o1.lastActiveTime)) + .collect(Collectors.toList()); + + assertTrue("Task order is not in sync with its recency", + mRecentTasks.getRawTasks().equals(tasksSortedByTime)); + } + + @Test public void testOrderedIteration() { mRecentTasks.setOnlyTestVisibleRange(); Task task1 = createTaskBuilder(".Task1").build(); diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java index f7719a6e55b2..95cbff9eeb12 100644 --- a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java +++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java @@ -38,6 +38,10 @@ public class HostTestUtils { private static final boolean SKIP_METHOD_LOG = "1".equals(System.getenv( "HOSTTEST_SKIP_METHOD_LOG")); + /** If true, we won't print class load log. */ + private static final boolean SKIP_CLASS_LOG = "1".equals(System.getenv( + "HOSTTEST_SKIP_CLASS_LOG")); + /** If true, we won't perform non-stub method direct call check. */ private static final boolean SKIP_NON_STUB_METHOD_CHECK = "1".equals(System.getenv( "HOSTTEST_SKIP_NON_STUB_METHOD_CHECK")); @@ -57,17 +61,34 @@ public class HostTestUtils { } /** - * Called from methods with FilterPolicy.Log. + * Trampoline method for method-call-hook. + */ + public static void callMethodCallHook( + Class<?> methodClass, + String methodName, + String methodDescriptor, + String callbackMethod + ) { + callStaticMethodByName(callbackMethod, methodClass, methodName, methodDescriptor); + } + + /** + * I can be used as + * {@code --default-method-call-hook + * com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall}. + * + * It logs every single methods called. */ public static void logMethodCall( - String methodClass, + Class<?> methodClass, String methodName, String methodDescriptor ) { if (SKIP_METHOD_LOG) { return; } - logPrintStream.println("# " + methodClass + "." + methodName + methodDescriptor); + logPrintStream.println("# method called: " + methodClass.getCanonicalName() + "." + + methodName + methodDescriptor); } private static final StackWalker sStackWalker = @@ -146,15 +167,19 @@ public class HostTestUtils { logPrintStream.println("! Class loaded: " + loadedClass.getCanonicalName() + " calling hook " + callbackMethod); + callStaticMethodByName(callbackMethod, loadedClass); + } + + private static void callStaticMethodByName(String classAndMethodName, Object... args) { // Forward the call to callbackMethod. - final int lastPeriod = callbackMethod.lastIndexOf("."); - final String className = callbackMethod.substring(0, lastPeriod); - final String methodName = callbackMethod.substring(lastPeriod + 1); + final int lastPeriod = classAndMethodName.lastIndexOf("."); + final String className = classAndMethodName.substring(0, lastPeriod); + final String methodName = classAndMethodName.substring(lastPeriod + 1); if (lastPeriod < 0 || className.isEmpty() || methodName.isEmpty()) { throw new HostTestException(String.format( "Unable to find class load hook: malformed method name \"%s\"", - callbackMethod)); + classAndMethodName)); } Class<?> clazz = null; @@ -169,13 +194,19 @@ public class HostTestUtils { "Unable to find class load hook: Class %s must be public", className)); } + Class<?>[] argTypes = new Class[args.length]; + for (int i = 0; i < args.length; i++) { + argTypes[i] = args[i].getClass(); + } + Method method = null; try { - method = clazz.getMethod(methodName, Class.class); + method = clazz.getMethod(methodName, argTypes); } catch (Exception e) { throw new HostTestException(String.format( "Unable to find class load hook: class %s doesn't have method %s" - + " (method must take exactly one parameter of type Class, and public static)", + + " (method must take exactly one parameter of type Class," + + " and public static)", className, methodName), e); } @@ -186,7 +217,7 @@ public class HostTestUtils { methodName, className)); } try { - method.invoke(null, loadedClass); + method.invoke(null, args); } catch (Exception e) { throw new HostTestException(String.format( "Unable to invoke class load hook %s.%s", @@ -194,4 +225,18 @@ public class HostTestUtils { methodName), e); } } + + /** + * I can be used as + * {@code --default-class-load-hook + * com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded}. + * + * It logs every loaded class. + */ + public static void logClassLoaded(Class<?> clazz) { + if (SKIP_CLASS_LOG) { + return; + } + logPrintStream.println("# class loaded: " + clazz.getCanonicalName()); + } } diff --git a/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt b/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt index 828d2a3e01c6..3f875272d0a8 100644 --- a/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt +++ b/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt @@ -6,8 +6,10 @@ --enable-non-stub-method-check # --no-non-stub-method-check -# --enable-method-logging - +#--default-method-call-hook +# com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall +#--default-class-load-hook +# com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded # Standard annotations. # Note, each line is a single argument, so we need newlines after each `--xxx-annotation`. diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt index 8db4b6961376..7531759aa106 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt @@ -17,6 +17,7 @@ package com.android.hoststubgen import com.android.hoststubgen.asm.ClassNodes import com.android.hoststubgen.filters.AnnotationBasedFilter +import com.android.hoststubgen.filters.DefaultHookInjectingFilter import com.android.hoststubgen.filters.ClassWidePolicyPropagatingFilter import com.android.hoststubgen.filters.ConstantFilter import com.android.hoststubgen.filters.FilterPolicy @@ -156,22 +157,29 @@ class HostStubGen(val options: HostStubGenOptions) { // This is used when a member (methods, fields, nested classes) don't get any polices // from upper filters. e.g. when a method has no annotations, then this filter will apply // the class-wide policy, if any. (if not, we'll fall back to the above filter.) - val classWidePropagator = ClassWidePolicyPropagatingFilter(filter) + filter = ClassWidePolicyPropagatingFilter(filter) + + // Inject default hooks from options. + filter = DefaultHookInjectingFilter( + options.defaultClassLoadHook, + options.defaultMethodCallHook, + filter + ) // Next, Java annotation based filter. filter = AnnotationBasedFilter( - errors, - allClasses, - options.stubAnnotations, - options.keepAnnotations, - options.stubClassAnnotations, - options.keepClassAnnotations, - options.throwAnnotations, - options.removeAnnotations, - options.substituteAnnotations, - options.nativeSubstituteAnnotations, - options.classLoadHookAnnotations, - classWidePropagator + errors, + allClasses, + options.stubAnnotations, + options.keepAnnotations, + options.stubClassAnnotations, + options.keepClassAnnotations, + options.throwAnnotations, + options.removeAnnotations, + options.substituteAnnotations, + options.nativeSubstituteAnnotations, + options.classLoadHookAnnotations, + filter ) // Next, "text based" filter, which allows to override polices without touching diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt index 9a54ecffc8c2..bbb7dab2c910 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt @@ -48,6 +48,9 @@ class HostStubGenOptions( var nativeSubstituteAnnotations: MutableSet<String> = mutableSetOf(), var classLoadHookAnnotations: MutableSet<String> = mutableSetOf(), + var defaultClassLoadHook: String? = null, + var defaultMethodCallHook: String? = null, + var intersectStubJars: MutableSet<String> = mutableSetOf(), var policyOverrideFile: String? = null, @@ -63,8 +66,6 @@ class HostStubGenOptions( var enablePreTrace: Boolean = false, var enablePostTrace: Boolean = false, - var enableMethodLogging: Boolean = false, - var enableNonStubMethodCallDetection: Boolean = true, ) { companion object { @@ -151,6 +152,12 @@ class HostStubGenOptions( ret.classLoadHookAnnotations += ensureUniqueAnnotation(ai.nextArgRequired(arg)) + "--default-class-load-hook" -> + ret.defaultClassLoadHook = ai.nextArgRequired(arg) + + "--default-method-call-hook" -> + ret.defaultMethodCallHook = ai.nextArgRequired(arg) + "--intersect-stub-jar" -> ret.intersectStubJars += ai.nextArgRequired(arg).ensureFileExists() @@ -167,9 +174,6 @@ class HostStubGenOptions( "--enable-post-trace" -> ret.enablePostTrace = true "--no-post-trace" -> ret.enablePostTrace = false - "--enable-method-logging" -> ret.enableMethodLogging = true - "--no-method-logging" -> ret.enableMethodLogging = false - "--enable-non-stub-method-check" -> ret.enableNonStubMethodCallDetection = true "--no-non-stub-method-check" -> ret.enableNonStubMethodCallDetection = false @@ -290,6 +294,8 @@ class HostStubGenOptions( substituteAnnotations=$substituteAnnotations, nativeSubstituteAnnotations=$nativeSubstituteAnnotations, classLoadHookAnnotations=$classLoadHookAnnotations, + defaultClassLoadHook=$defaultClassLoadHook, + defaultMethodCallHook=$defaultMethodCallHook, intersectStubJars=$intersectStubJars, policyOverrideFile=$policyOverrideFile, defaultPolicy=$defaultPolicy, @@ -299,7 +305,6 @@ class HostStubGenOptions( enableClassChecker=$enableClassChecker, enablePreTrace=$enablePreTrace, enablePostTrace=$enablePostTrace, - enableMethodLogging=$enableMethodLogging, enableNonStubMethodCallDetection=$enableNonStubMethodCallDetection, } """.trimIndent() diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt index 9fbd6d09bfb0..7d7852ab162e 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt @@ -31,3 +31,23 @@ fun normalizeTextLine(s: String): String { // Remove surrounding whitespace. return uncommented.trim() } + +fun <T> addLists(a: List<T>, b: List<T>): List<T> { + if (a.isEmpty()) { + return b + } + if (b.isEmpty()) { + return a + } + return a + b +} + +fun <T> addNonNullElement(a: List<T>, b: T?): List<T> { + if (b == null) { + return a + } + if (a.isEmpty()) { + return listOf(b) + } + return a + b +}
\ No newline at end of file diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt index 454569d2f1c5..3f492e834637 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt @@ -19,6 +19,7 @@ import com.android.hoststubgen.ClassParseException import com.android.hoststubgen.HostStubGenErrors import com.android.hoststubgen.HostStubGenInternalException import com.android.hoststubgen.InvalidAnnotationException +import com.android.hoststubgen.addNonNullElement import com.android.hoststubgen.asm.ClassNodes import com.android.hoststubgen.asm.findAnnotationValueAsString import com.android.hoststubgen.asm.findAnyAnnotation @@ -253,14 +254,14 @@ class AnnotationBasedFilter( return null } - override fun getClassLoadHook(className: String): String? { - classes.getClass(className).let { cn -> + override fun getClassLoadHooks(className: String): List<String> { + val e = classes.getClass(className).let { cn -> findAnyAnnotation(classLoadHookAnnotations, cn.visibleAnnotations, cn.invisibleAnnotations)?.let { an -> - return getAnnotationField(an, "value")?.toHumanReadableMethodName() + getAnnotationField(an, "value")?.toHumanReadableMethodName() } } - return null + return addNonNullElement(super.getClassLoadHooks(className), e) } private data class MethodKey(val name: String, val desc: String) diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt new file mode 100644 index 000000000000..d771003a955d --- /dev/null +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.hoststubgen.filters + +import com.android.hoststubgen.addLists + +class DefaultHookInjectingFilter( + defaultClassLoadHook: String?, + defaultMethodCallHook: String?, + fallback: OutputFilter +) : DelegatingFilter(fallback) { + /** + * Create a List containing a single element [e], if e != null. Otherwise, returns + * an empty list. + */ + private fun toSingleList(e: String?): List<String> { + if (e == null) { + return emptyList() + } + return listOf(e) + } + + private val defaultClassLoadHookAsList: List<String> = toSingleList(defaultClassLoadHook) + private val defaultMethodCallHookAsList: List<String> = toSingleList(defaultMethodCallHook) + + override fun getClassLoadHooks(className: String): List<String> { + return addLists(super.getClassLoadHooks(className), defaultClassLoadHookAsList) + } + + override fun getMethodCallHooks( + className: String, + methodName: String, + descriptor: String + ): List<String> { + return addLists( + super.getMethodCallHooks(className, methodName, descriptor), + defaultMethodCallHookAsList, + ) + } +}
\ No newline at end of file diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt index f0763c4ba097..45f61c5b2c22 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt @@ -66,7 +66,15 @@ abstract class DelegatingFilter( return fallback.getNativeSubstitutionClass(className) } - override fun getClassLoadHook(className: String): String? { - return fallback.getClassLoadHook(className) + override fun getClassLoadHooks(className: String): List<String> { + return fallback.getClassLoadHooks(className) + } + + override fun getMethodCallHooks( + className: String, + methodName: String, + descriptor: String + ): List<String> { + return fallback.getMethodCallHooks(className, methodName, descriptor) } } diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt index f3551d49bd36..5659a35170c1 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt @@ -16,6 +16,7 @@ package com.android.hoststubgen.filters import com.android.hoststubgen.UnknownApiException +import com.android.hoststubgen.addNonNullElement import com.android.hoststubgen.asm.ClassNodes import com.android.hoststubgen.asm.toHumanReadableClassName import com.android.hoststubgen.asm.toHumanReadableMethodName @@ -127,9 +128,9 @@ class InMemoryOutputFilter( mNativeSubstitutionClasses[getClassKey(from)] = to.toHumanReadableClassName() } - override fun getClassLoadHook(className: String): String? { - return mClassLoadHooks[getClassKey(className)] - ?: super.getClassLoadHook(className) + override fun getClassLoadHooks(className: String): List<String> { + return addNonNullElement(super.getClassLoadHooks(className), + mClassLoadHooks[getClassKey(className)]) } fun setClassLoadHook(className: String, methodName: String) { diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt index 392ee4b81613..3df16ffa99b3 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt @@ -71,11 +71,22 @@ abstract class OutputFilter { } /** - * Return a "class load hook" method name for a given class. + * Return a "class load hook" class name for a given class. * * (which corresponds to @HostSideTestClassLoadHook of the standard annotations.) */ - open fun getClassLoadHook(className: String): String? { - return null + open fun getClassLoadHooks(className: String): List<String> { + return emptyList() + } + + /** + * Return the "method call hook" class name. + * + * The class has to have a function with the following signature: + * `public static void onMethodCalled(Class<?> clazz, String name, String descriptor)`. + */ + open fun getMethodCallHooks(className: String, methodName: String, descriptor: String): + List<String> { + return emptyList() } }
\ No newline at end of file diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt index ac068861ec8d..57b668954f98 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt @@ -45,7 +45,7 @@ class ImplGeneratingAdapter( return policy.needsInImpl } - private var classLoadHookMethod: String? = null + private var classLoadHooks: List<String> = emptyList() override fun visit( version: Int, @@ -57,22 +57,22 @@ class ImplGeneratingAdapter( ) { super.visit(version, access, name, signature, superName, interfaces) - classLoadHookMethod = filter.getClassLoadHook(currentClassName) + classLoadHooks = filter.getClassLoadHooks(currentClassName) // classLoadHookMethod is non-null, then we need to inject code to call it // in the class initializer. // If the target class already has a class initializer, then we need to inject code to it. // Otherwise, we need to create one. - classLoadHookMethod?.let { callback -> - log.d(" ClassLoadHook: $callback") + if (classLoadHooks.isNotEmpty()) { + log.d(" ClassLoadHooks: $classLoadHooks") if (!classes.hasClassInitializer(currentClassName)) { - injectClassLoadHook(callback) + injectClassLoadHook() } } } - private fun injectClassLoadHook(callback: String) { + private fun injectClassLoadHook() { writeRawMembers { // Create a class initializer to call onClassLoaded(). // Each class can only have at most one class initializer, but the base class @@ -87,7 +87,7 @@ class ImplGeneratingAdapter( // Method prologue mv.visitCode() - writeClassLoadHookCall(mv) + writeClassLoadHookCalls(mv) mv.visitInsn(Opcodes.RETURN) // Method epilogue @@ -97,21 +97,23 @@ class ImplGeneratingAdapter( } } - private fun writeClassLoadHookCall(mv: MethodVisitor) { - // First argument: the class type. - mv.visitLdcInsn(Type.getType("L" + currentClassName + ";")) - - // Second argument: method name - mv.visitLdcInsn(classLoadHookMethod) - - // Call HostTestUtils.onClassLoaded(). - mv.visitMethodInsn( - Opcodes.INVOKESTATIC, - HostTestUtils.CLASS_INTERNAL_NAME, - "onClassLoaded", - "(Ljava/lang/Class;Ljava/lang/String;)V", - false - ) + private fun writeClassLoadHookCalls(mv: MethodVisitor) { + classLoadHooks.forEach { classLoadHook -> + // First argument: the class type. + mv.visitLdcInsn(Type.getType("L" + currentClassName + ";")) + + // Second argument: method name + mv.visitLdcInsn(classLoadHook) + + // Call HostTestUtils.onClassLoaded(). + mv.visitMethodInsn( + Opcodes.INVOKESTATIC, + HostTestUtils.CLASS_INTERNAL_NAME, + "onClassLoaded", + "(Ljava/lang/Class;Ljava/lang/String;)V", + false + ) + } } override fun updateAccessFlags( @@ -138,20 +140,22 @@ class ImplGeneratingAdapter( var innerVisitor = superVisitor // If method logging is enabled, inject call to the logging method. - if (options.enableMethodLogging) { - innerVisitor = LogInjectingMethodAdapter( - access, - name, - descriptor, - signature, - exceptions, - innerVisitor, - ) + val methodCallHooks = filter.getMethodCallHooks(currentClassName, name, descriptor) + if (methodCallHooks.isNotEmpty()) { + innerVisitor = MethodCallHookInjectingAdapter( + access, + name, + descriptor, + signature, + exceptions, + innerVisitor, + methodCallHooks, + ) } // If this class already has a class initializer and a class load hook is needed, then // we inject code. - if (classLoadHookMethod != null && + if (classLoadHooks.isNotEmpty() && name == CLASS_INITIALIZER_NAME && descriptor == CLASS_INITIALIZER_DESC) { innerVisitor = ClassLoadHookInjectingMethodAdapter( @@ -283,29 +287,37 @@ class ImplGeneratingAdapter( } /** - * A method adapter that injects a call to HostTestUtils.logMethodCall() to every method. + * Inject calls to the method call hooks. * * Note, when the target method is a constructor, it may contain calls to `super(...)` or * `this(...)`. The logging code will be injected *before* such calls. */ - private inner class LogInjectingMethodAdapter( + private inner class MethodCallHookInjectingAdapter( access: Int, val name: String, val descriptor: String, signature: String?, exceptions: Array<String>?, - next: MethodVisitor? + next: MethodVisitor?, + val hooks: List<String>, ) : MethodVisitor(OPCODE_VERSION, next) { override fun visitCode() { super.visitCode() - visitLdcInsn(currentClassName) - visitLdcInsn(name) - visitLdcInsn(descriptor) - visitMethodInsn(Opcodes.INVOKESTATIC, + + hooks.forEach { hook -> + mv.visitLdcInsn(Type.getType("L" + currentClassName + ";")) + visitLdcInsn(name) + visitLdcInsn(descriptor) + visitLdcInsn(hook) + + visitMethodInsn( + Opcodes.INVOKESTATIC, HostTestUtils.CLASS_INTERNAL_NAME, - "logMethodCall", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", - false) + "callMethodCallHook", + "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", + false + ) + } } } @@ -323,7 +335,7 @@ class ImplGeneratingAdapter( override fun visitCode() { super.visitCode() - writeClassLoadHookCall(this) + writeClassLoadHookCalls(this) } } diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp index 8c76a612020f..05d6a43cdb0f 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp @@ -53,6 +53,46 @@ java_genrule_host { ], } +// Same as "hoststubgen-test-tiny-framework-host", but with more options, to test more hoststubgen +// features. +java_genrule_host { + name: "hoststubgen-test-tiny-framework-host-ext", + defaults: ["hoststubgen-command-defaults"], + cmd: hoststubgen_common_options + + "--in-jar $(location :hoststubgen-test-tiny-framework) " + + "--policy-override-file $(location policy-override-tiny-framework.txt) " + + + // More options. + "--default-method-call-hook com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall " + + "--default-class-load-hook com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded ", + srcs: [ + ":hoststubgen-test-tiny-framework", + "policy-override-tiny-framework.txt", + ], +} + +java_genrule_host { + name: "hoststubgen-test-tiny-framework-host-ext-stub", + cmd: "cp $(in) $(out)", + srcs: [ + ":hoststubgen-test-tiny-framework-host-ext{host_stub.jar}", + ], + out: [ + "host_stub.jar", + ], +} + +java_genrule_host { + name: "hoststubgen-test-tiny-framework-host-ext-impl", + cmd: "cp $(in) $(out)", + srcs: [ + ":hoststubgen-test-tiny-framework-host-ext{host_impl.jar}", + ], + out: [ + "host_impl.jar", + ], +} + // Compile the test jar, using 2 rules. // 1. Build the test against the stub. java_library_host { @@ -123,6 +163,30 @@ java_genrule_host { visibility: ["//visibility:private"], } +java_genrule_host { + name: "hoststubgen-test-tiny-framework-host-ext-stub-dump", + defaults: ["hoststubgen-jar-dump-defaults"], + srcs: [ + ":hoststubgen-test-tiny-framework-host-ext-stub", + ], + out: [ + "12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt", + ], + visibility: ["//visibility:private"], +} + +java_genrule_host { + name: "hoststubgen-test-tiny-framework-host-ext-impl-dump", + defaults: ["hoststubgen-jar-dump-defaults"], + srcs: [ + ":hoststubgen-test-tiny-framework-host-ext-impl", + ], + out: [ + "13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt", + ], + visibility: ["//visibility:private"], +} + // Run it with `atest`. Compare the dump of the jar files to the golden output. python_test_host { name: "tiny-framework-dump-test", @@ -136,6 +200,8 @@ python_test_host { "hoststubgen-test-tiny-framework-host-stub-dump", "hoststubgen-test-tiny-framework-host-impl-dump", "hoststubgen-test-tiny-framework-orig-dump", + "hoststubgen-test-tiny-framework-host-ext-stub-dump", + "hoststubgen-test-tiny-framework-host-ext-impl-dump", ], test_suites: ["general-tests"], } diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/diff-and-update-golden.sh b/tools/hoststubgen/hoststubgen/test-tiny-framework/diff-and-update-golden.sh index 4d588694b8da..639fb16c4251 100755 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/diff-and-update-golden.sh +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/diff-and-update-golden.sh @@ -112,7 +112,7 @@ done if (( $three_way )) ; then echo "# Running 3-way diff with meld..." - run meld ${files[*]} & + run meld ${files[0]} ${files[1]} ${files[2]} & fi if (( $two_way )) ; then diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt new file mode 100644 index 000000000000..43ceec42660d --- /dev/null +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt @@ -0,0 +1,837 @@ +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class + Compiled from "TinyFrameworkCallerCheck.java" +class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl + minor version: 0 + major version: 61 + flags: (0x0020) ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 2, attributes: 4 + private com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl(); + descriptor: ()V + flags: (0x0002) ACC_PRIVATE + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public static int getOneStub(); + descriptor: ()I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=0, args_size=0 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestStub +} +InnerClasses: + private static #x= #x of #x; // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck +SourceFile: "TinyFrameworkCallerCheck.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.class + Compiled from "TinyFrameworkCallerCheck.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 3, attributes: 5 + public com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public static int getOne_withCheck(); + descriptor: ()I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=0, args_size=0 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public static int getOne_noCheck(); + descriptor: ()I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=0, args_size=0 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow +} +InnerClasses: + private static #x= #x of #x; // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck +SourceFile: "TinyFrameworkCallerCheck.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +NestMembers: + com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.class + Compiled from "TinyFrameworkClassAnnotations.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 5, attributes: 3 + public int stub; + descriptor: I + flags: (0x0001) ACC_PUBLIC + RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestStub + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestStub + + public int addOne(int); + descriptor: (I)I + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=2, args_size=2 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestStub + + public int addTwo(int); + descriptor: (I)I + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=2, args_size=2 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public static int nativeAddThree(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public java.lang.String visibleButUsesUnsupportedMethod(); + descriptor: ()Ljava/lang/String; + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestStub +} +SourceFile: "TinyFrameworkClassAnnotations.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestStub + x: #x(#x=s#x) + android.hosttest.annotation.HostSideTestClassLoadHook( + value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded" + ) +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.class + Compiled from "TinyFrameworkClassClassWideAnnotations.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations + super_class: #x // java/lang/Object + interfaces: 0, fields: 3, methods: 8, attributes: 3 + public int stub; + descriptor: I + flags: (0x0001) ACC_PUBLIC + + public int keep; + descriptor: I + flags: (0x0001) ACC_PUBLIC + + public int remove; + descriptor: I + flags: (0x0001) ACC_PUBLIC + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public int addOne(int); + descriptor: (I)I + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=2, args_size=2 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public int addOneInner(int); + descriptor: (I)I + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=2, args_size=2 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public void toBeRemoved(java.lang.String); + descriptor: (Ljava/lang/String;)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=2, args_size=2 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public int addTwo(int); + descriptor: (I)I + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=2, args_size=2 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public static int nativeAddThree(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public java.lang.String unsupportedMethod(); + descriptor: ()Ljava/lang/String; + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public java.lang.String visibleButUsesUnsupportedMethod(); + descriptor: ()Ljava/lang/String; + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow +} +SourceFile: "TinyFrameworkClassClassWideAnnotations.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class + Compiled from "TinyFrameworkClassLoadHook.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 3, attributes: 3 + public static final java.util.Set<java.lang.Class<?>> sLoadedClasses; + descriptor: Ljava/util/Set; + flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL + Signature: #x // Ljava/util/Set<Ljava/lang/Class<*>;>; + + private com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook(); + descriptor: ()V + flags: (0x0002) ACC_PRIVATE + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public static void onClassLoaded(java.lang.Class<?>); + descriptor: (Ljava/lang/Class;)V + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + Signature: #x // (Ljava/lang/Class<*>;)V + + static {}; + descriptor: ()V + flags: (0x0008) ACC_STATIC + Code: + stack=3, locals=0, args_size=0 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow +} +SourceFile: "TinyFrameworkClassLoadHook.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.class + Compiled from "TinyFrameworkClassWithInitializer.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 3 + public static boolean sInitialized; + descriptor: Z + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + static {}; + descriptor: ()V + flags: (0x0008) ACC_STATIC + Code: + stack=3, locals=0, args_size=0 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow +} +SourceFile: "TinyFrameworkClassWithInitializer.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x(#x=s#x) + android.hosttest.annotation.HostSideTestClassLoadHook( + value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded" + ) + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class + Compiled from "TinyFrameworkExceptionTester.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 2, attributes: 3 + public com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public static int testException(); + descriptor: ()I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=0, args_size=0 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow +} +SourceFile: "TinyFrameworkExceptionTester.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.class + Compiled from "TinyFrameworkForTextPolicy.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 5, attributes: 2 + public int stub; + descriptor: I + flags: (0x0001) ACC_PUBLIC + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public int addOne(int); + descriptor: (I)I + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=2, args_size=2 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public int addTwo(int); + descriptor: (I)I + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=2, args_size=2 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public static int nativeAddThree(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public java.lang.String visibleButUsesUnsupportedMethod(); + descriptor: ()Ljava/lang/String; + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow +} +SourceFile: "TinyFrameworkForTextPolicy.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class + Compiled from "TinyFrameworkNative.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 5, attributes: 3 + public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public static native int nativeAddTwo(int); + descriptor: (I)I + flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE + + public static int nativeAddTwo_should_be_like_this(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public static native long nativeLongPlus(long, long); + descriptor: (JJ)J + flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE + + public static long nativeLongPlus_should_be_like_this(long, long); + descriptor: (JJ)J + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=4, args_size=2 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow +} +SourceFile: "TinyFrameworkNative.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub + x: #x(#x=s#x) + android.hosttest.annotation.HostSideTestNativeSubstitutionClass( + value="TinyFrameworkNative_host" + ) +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass.class + Compiled from "TinyFrameworkNestedClasses.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 1, attributes: 4 + public int value; + descriptor: I + flags: (0x0001) ACC_PUBLIC + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass(int); + descriptor: (I)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=2, args_size=2 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow +} +InnerClasses: + public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +SourceFile: "TinyFrameworkNestedClasses.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class + Compiled from "TinyFrameworkNestedClasses.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass + super_class: #x // java/lang/Object + interfaces: 0, fields: 2, methods: 1, attributes: 5 + public int value; + descriptor: I + flags: (0x0001) ACC_PUBLIC + + final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0; + descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses); + descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=2, args_size=2 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow +} +InnerClasses: + public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +SourceFile: "TinyFrameworkNestedClasses.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class + Compiled from "TinyFrameworkNestedClasses.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 5 + public int value; + descriptor: I + flags: (0x0001) ACC_PUBLIC + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public static java.util.function.Supplier<java.lang.Integer> getSupplier_static(); + descriptor: ()Ljava/util/function/Supplier; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=0, args_size=0 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; +} +InnerClasses: + public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 +SourceFile: "TinyFrameworkNestedClasses.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class + Compiled from "TinyFrameworkNestedClasses.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass extends com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass + super_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass + interfaces: 0, fields: 0, methods: 1, attributes: 4 + public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass(int); + descriptor: (I)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=2, args_size=2 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow +} +InnerClasses: + public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + public static #x= #x of #x; // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +SourceFile: "TinyFrameworkNestedClasses.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class + Compiled from "TinyFrameworkNestedClasses.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + super_class: #x // java/lang/Object + interfaces: 0, fields: 2, methods: 4, attributes: 5 + public final java.util.function.Supplier<java.lang.Integer> mSupplier; + descriptor: Ljava/util/function/Supplier; + flags: (0x0011) ACC_PUBLIC, ACC_FINAL + Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + + public static final java.util.function.Supplier<java.lang.Integer> sSupplier; + descriptor: Ljava/util/function/Supplier; + flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL + Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public java.util.function.Supplier<java.lang.Integer> getSupplier(); + descriptor: ()Ljava/util/function/Supplier; + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + + public static java.util.function.Supplier<java.lang.Integer> getSupplier_static(); + descriptor: ()Ljava/util/function/Supplier; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=0, args_size=0 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + + static {}; + descriptor: ()V + flags: (0x0008) ACC_STATIC + Code: + stack=3, locals=0, args_size=0 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow +} +InnerClasses: + #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 + #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 + #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 + #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 + public static #x= #x of #x; // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 +SourceFile: "TinyFrameworkNestedClasses.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +NestMembers: + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt new file mode 100644 index 000000000000..874789e23607 --- /dev/null +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt @@ -0,0 +1,2348 @@ +## Class: android/hosttest/annotation/HostSideTestClassLoadHook.class + Compiled from "HostSideTestClassLoadHook.java" +public interface android.hosttest.annotation.HostSideTestClassLoadHook extends java.lang.annotation.Annotation + minor version: 0 + major version: 61 + flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION + this_class: #x // android/hosttest/annotation/HostSideTestClassLoadHook + super_class: #x // java/lang/Object + interfaces: 1, fields: 0, methods: 2, attributes: 2 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class android/hosttest/annotation/HostSideTestClassLoadHook + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public abstract java.lang.String value(); + descriptor: ()Ljava/lang/String; + flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT +} +SourceFile: "HostSideTestClassLoadHook.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + x: #x(#x=[e#x.#x]) + java.lang.annotation.Target( + value=[Ljava/lang/annotation/ElementType;.TYPE] + ) + x: #x(#x=e#x.#x) + java.lang.annotation.Retention( + value=Ljava/lang/annotation/RetentionPolicy;.CLASS + ) +## Class: android/hosttest/annotation/HostSideTestKeep.class + Compiled from "HostSideTestKeep.java" +public interface android.hosttest.annotation.HostSideTestKeep extends java.lang.annotation.Annotation + minor version: 0 + major version: 61 + flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION + this_class: #x // android/hosttest/annotation/HostSideTestKeep + super_class: #x // java/lang/Object + interfaces: 1, fields: 0, methods: 1, attributes: 2 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class android/hosttest/annotation/HostSideTestKeep + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return +} +SourceFile: "HostSideTestKeep.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x]) + java.lang.annotation.Target( + value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR] + ) + x: #x(#x=e#x.#x) + java.lang.annotation.Retention( + value=Ljava/lang/annotation/RetentionPolicy;.CLASS + ) +## Class: android/hosttest/annotation/HostSideTestNativeSubstitutionClass.class + Compiled from "HostSideTestNativeSubstitutionClass.java" +public interface android.hosttest.annotation.HostSideTestNativeSubstitutionClass extends java.lang.annotation.Annotation + minor version: 0 + major version: 61 + flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION + this_class: #x // android/hosttest/annotation/HostSideTestNativeSubstitutionClass + super_class: #x // java/lang/Object + interfaces: 1, fields: 0, methods: 2, attributes: 2 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class android/hosttest/annotation/HostSideTestNativeSubstitutionClass + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public abstract java.lang.String value(); + descriptor: ()Ljava/lang/String; + flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT +} +SourceFile: "HostSideTestNativeSubstitutionClass.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + x: #x(#x=[e#x.#x]) + java.lang.annotation.Target( + value=[Ljava/lang/annotation/ElementType;.TYPE] + ) + x: #x(#x=e#x.#x) + java.lang.annotation.Retention( + value=Ljava/lang/annotation/RetentionPolicy;.CLASS + ) +## Class: android/hosttest/annotation/HostSideTestRemove.class + Compiled from "HostSideTestRemove.java" +public interface android.hosttest.annotation.HostSideTestRemove extends java.lang.annotation.Annotation + minor version: 0 + major version: 61 + flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION + this_class: #x // android/hosttest/annotation/HostSideTestRemove + super_class: #x // java/lang/Object + interfaces: 1, fields: 0, methods: 1, attributes: 2 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class android/hosttest/annotation/HostSideTestRemove + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return +} +SourceFile: "HostSideTestRemove.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x]) + java.lang.annotation.Target( + value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR] + ) + x: #x(#x=e#x.#x) + java.lang.annotation.Retention( + value=Ljava/lang/annotation/RetentionPolicy;.CLASS + ) +## Class: android/hosttest/annotation/HostSideTestStub.class + Compiled from "HostSideTestStub.java" +public interface android.hosttest.annotation.HostSideTestStub extends java.lang.annotation.Annotation + minor version: 0 + major version: 61 + flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION + this_class: #x // android/hosttest/annotation/HostSideTestStub + super_class: #x // java/lang/Object + interfaces: 1, fields: 0, methods: 1, attributes: 2 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class android/hosttest/annotation/HostSideTestStub + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return +} +SourceFile: "HostSideTestStub.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x]) + java.lang.annotation.Target( + value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR] + ) + x: #x(#x=e#x.#x) + java.lang.annotation.Retention( + value=Ljava/lang/annotation/RetentionPolicy;.CLASS + ) +## Class: android/hosttest/annotation/HostSideTestSubstitute.class + Compiled from "HostSideTestSubstitute.java" +public interface android.hosttest.annotation.HostSideTestSubstitute extends java.lang.annotation.Annotation + minor version: 0 + major version: 61 + flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION + this_class: #x // android/hosttest/annotation/HostSideTestSubstitute + super_class: #x // java/lang/Object + interfaces: 1, fields: 0, methods: 2, attributes: 2 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class android/hosttest/annotation/HostSideTestSubstitute + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public abstract java.lang.String suffix(); + descriptor: ()Ljava/lang/String; + flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT +} +SourceFile: "HostSideTestSubstitute.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + x: #x(#x=[e#x.#x]) + java.lang.annotation.Target( + value=[Ljava/lang/annotation/ElementType;.METHOD] + ) + x: #x(#x=e#x.#x) + java.lang.annotation.Retention( + value=Ljava/lang/annotation/RetentionPolicy;.CLASS + ) +## Class: android/hosttest/annotation/HostSideTestThrow.class + Compiled from "HostSideTestThrow.java" +public interface android.hosttest.annotation.HostSideTestThrow extends java.lang.annotation.Annotation + minor version: 0 + major version: 61 + flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION + this_class: #x // android/hosttest/annotation/HostSideTestThrow + super_class: #x // java/lang/Object + interfaces: 1, fields: 0, methods: 1, attributes: 2 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class android/hosttest/annotation/HostSideTestThrow + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return +} +SourceFile: "HostSideTestThrow.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + x: #x(#x=[e#x.#x,e#x.#x]) + java.lang.annotation.Target( + value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR] + ) + x: #x(#x=e#x.#x) + java.lang.annotation.Retention( + value=Ljava/lang/annotation/RetentionPolicy;.CLASS + ) +## Class: android/hosttest/annotation/HostSideTestWholeClassKeep.class + Compiled from "HostSideTestWholeClassKeep.java" +public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends java.lang.annotation.Annotation + minor version: 0 + major version: 61 + flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION + this_class: #x // android/hosttest/annotation/HostSideTestWholeClassKeep + super_class: #x // java/lang/Object + interfaces: 1, fields: 0, methods: 1, attributes: 2 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class android/hosttest/annotation/HostSideTestWholeClassKeep + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return +} +SourceFile: "HostSideTestWholeClassKeep.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + x: #x(#x=[e#x.#x]) + java.lang.annotation.Target( + value=[Ljava/lang/annotation/ElementType;.TYPE] + ) + x: #x(#x=e#x.#x) + java.lang.annotation.Retention( + value=Ljava/lang/annotation/RetentionPolicy;.CLASS + ) +## Class: android/hosttest/annotation/HostSideTestWholeClassStub.class + Compiled from "HostSideTestWholeClassStub.java" +public interface android.hosttest.annotation.HostSideTestWholeClassStub extends java.lang.annotation.Annotation + minor version: 0 + major version: 61 + flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION + this_class: #x // android/hosttest/annotation/HostSideTestWholeClassStub + super_class: #x // java/lang/Object + interfaces: 1, fields: 0, methods: 1, attributes: 2 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class android/hosttest/annotation/HostSideTestWholeClassStub + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return +} +SourceFile: "HostSideTestWholeClassStub.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + x: #x(#x=[e#x.#x]) + java.lang.annotation.Target( + value=[Ljava/lang/annotation/ElementType;.TYPE] + ) + x: #x(#x=e#x.#x) + java.lang.annotation.Retention( + value=Ljava/lang/annotation/RetentionPolicy;.CLASS + ) +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class + Compiled from "TinyFrameworkCallerCheck.java" +class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl + minor version: 0 + major version: 61 + flags: (0x0020) ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 4, attributes: 4 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + private com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl(); + descriptor: ()V + flags: (0x0002) ACC_PRIVATE + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl; + + public static int getOneKeep(); + descriptor: ()I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl + x: ldc #x // String getOneKeep + x: ldc #x // String ()I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl + x: ldc #x // String getOneKeep + x: ldc #x // String ()I + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: iconst_1 + x: ireturn + LineNumberTable: + RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestKeep + + public static int getOneStub(); + descriptor: ()I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl + x: ldc #x // String getOneStub + x: ldc #x // String ()I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: iconst_1 + x: ireturn + LineNumberTable: + RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestStub +} +InnerClasses: + private static #x= #x of #x; // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck +SourceFile: "TinyFrameworkCallerCheck.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.class + Compiled from "TinyFrameworkCallerCheck.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 4, attributes: 5 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck; + + public static int getOne_withCheck(); + descriptor: ()I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck + x: ldc #x // String getOne_withCheck + x: ldc #x // String ()I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneKeep:()I + x: ireturn + LineNumberTable: + + public static int getOne_noCheck(); + descriptor: ()I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck + x: ldc #x // String getOne_noCheck + x: ldc #x // String ()I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneStub:()I + x: ireturn + LineNumberTable: +} +InnerClasses: + private static #x= #x of #x; // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck +SourceFile: "TinyFrameworkCallerCheck.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +NestMembers: + com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.class + Compiled from "TinyFrameworkClassAnnotations.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations + super_class: #x // java/lang/Object + interfaces: 0, fields: 2, methods: 8, attributes: 3 + public int stub; + descriptor: I + flags: (0x0001) ACC_PUBLIC + RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestStub + + public int keep; + descriptor: I + flags: (0x0001) ACC_PUBLIC + RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestKeep + + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations + x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: aload_0 + x: iconst_1 + x: putfield #x // Field stub:I + x: aload_0 + x: iconst_2 + x: putfield #x // Field keep:I + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations; + RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestStub + + public int addOne(int); + descriptor: (I)I + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations + x: ldc #x // String addOne + x: ldc #x // String (I)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: iload_1 + x: invokevirtual #x // Method addOneInner:(I)I + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations; + 11 6 1 value I + RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestStub + + public int addOneInner(int); + descriptor: (I)I + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations + x: ldc #x // String addOneInner + x: ldc #x // String (I)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations + x: ldc #x // String addOneInner + x: ldc #x // String (I)I + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: iload_1 + x: iconst_1 + x: iadd + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 26 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations; + 26 4 1 value I + RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestKeep + + public int addTwo(int); + descriptor: (I)I + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations + x: ldc #x // String addTwo + x: ldc #x // String (I)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: iload_1 + x: iconst_2 + x: iadd + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations; + 11 4 1 value I + + public static int nativeAddThree(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations + x: ldc #x // String nativeAddThree + x: ldc #x // String (I)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: iload_0 + x: iconst_3 + x: iadd + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 4 0 value I + + public java.lang.String unsupportedMethod(); + descriptor: ()Ljava/lang/String; + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations + x: ldc #x // String unsupportedMethod + x: ldc #x // String ()Ljava/lang/String; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations + x: ldc #x // String unsupportedMethod + x: ldc #x // String ()Ljava/lang/String; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Unreachable + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestThrow + + public java.lang.String visibleButUsesUnsupportedMethod(); + descriptor: ()Ljava/lang/String; + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations + x: ldc #x // String visibleButUsesUnsupportedMethod + x: ldc #x // String ()Ljava/lang/String; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String; + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations; + RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestStub +} +SourceFile: "TinyFrameworkClassAnnotations.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestStub + x: #x(#x=s#x) + android.hosttest.annotation.HostSideTestClassLoadHook( + value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded" + ) +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.class + Compiled from "TinyFrameworkClassClassWideAnnotations.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations + super_class: #x // java/lang/Object + interfaces: 0, fields: 3, methods: 9, attributes: 3 + public int stub; + descriptor: I + flags: (0x0001) ACC_PUBLIC + + public int keep; + descriptor: I + flags: (0x0001) ACC_PUBLIC + + public int remove; + descriptor: I + flags: (0x0001) ACC_PUBLIC + + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: aload_0 + x: iconst_1 + x: putfield #x // Field stub:I + x: aload_0 + x: iconst_2 + x: putfield #x // Field keep:I + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations; + + public int addOne(int); + descriptor: (I)I + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations + x: ldc #x // String addOne + x: ldc #x // String (I)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: iload_1 + x: invokevirtual #x // Method addOneInner:(I)I + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations; + 11 6 1 value I + + public int addOneInner(int); + descriptor: (I)I + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations + x: ldc #x // String addOneInner + x: ldc #x // String (I)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: iload_1 + x: iconst_1 + x: iadd + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations; + 11 4 1 value I + + public void toBeRemoved(java.lang.String); + descriptor: (Ljava/lang/String;)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations + x: ldc #x // String toBeRemoved + x: ldc #x // String (Ljava/lang/String;)V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: new #x // class java/lang/RuntimeException + x: dup + x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V + x: athrow + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations; + 11 8 1 foo Ljava/lang/String; + + public int addTwo(int); + descriptor: (I)I + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations + x: ldc #x // String addTwo + x: ldc #x // String (I)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: iload_1 + x: iconst_2 + x: iadd + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations; + 11 4 1 value I + + public static int nativeAddThree(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations + x: ldc #x // String nativeAddThree + x: ldc #x // String (I)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: iload_0 + x: iconst_3 + x: iadd + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 4 0 value I + + public java.lang.String unsupportedMethod(); + descriptor: ()Ljava/lang/String; + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations + x: ldc #x // String unsupportedMethod + x: ldc #x // String ()Ljava/lang/String; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String This value shouldn\'t be seen on the host side. + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 3 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations; + + public java.lang.String visibleButUsesUnsupportedMethod(); + descriptor: ()Ljava/lang/String; + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations + x: ldc #x // String visibleButUsesUnsupportedMethod + x: ldc #x // String ()Ljava/lang/String; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String; + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations; +} +SourceFile: "TinyFrameworkClassClassWideAnnotations.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class + Compiled from "TinyFrameworkClassLoadHook.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 3, attributes: 3 + public static final java.util.Set<java.lang.Class<?>> sLoadedClasses; + descriptor: Ljava/util/Set; + flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL + Signature: #x // Ljava/util/Set<Ljava/lang/Class<*>;>; + + private com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook(); + descriptor: ()V + flags: (0x0002) ACC_PRIVATE + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook; + + public static void onClassLoaded(java.lang.Class<?>); + descriptor: (Ljava/lang/Class;)V + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook + x: ldc #x // String onClassLoaded + x: ldc #x // String (Ljava/lang/Class;)V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: getstatic #x // Field sLoadedClasses:Ljava/util/Set; + x: aload_0 + x: invokeinterface #x, 2 // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z + x: pop + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 11 0 clazz Ljava/lang/Class; + LocalVariableTypeTable: + Start Length Slot Name Signature + 11 11 0 clazz Ljava/lang/Class<*>; + Signature: #x // (Ljava/lang/Class<*>;)V + + static {}; + descriptor: ()V + flags: (0x0008) ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook + x: ldc #x // String <clinit> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: new #x // class java/util/HashSet + x: dup + x: invokespecial #x // Method java/util/HashSet."<init>":()V + x: putstatic #x // Field sLoadedClasses:Ljava/util/Set; + x: return + LineNumberTable: +} +SourceFile: "TinyFrameworkClassLoadHook.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.class + Compiled from "TinyFrameworkClassWithInitializer.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 3 + public static boolean sInitialized; + descriptor: Z + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer; + + static {}; + descriptor: ()V + flags: (0x0008) ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer + x: ldc #x // String <clinit> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer + x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: iconst_1 + x: putstatic #x // Field sInitialized:Z + x: return + LineNumberTable: +} +SourceFile: "TinyFrameworkClassWithInitializer.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x(#x=s#x) + android.hosttest.annotation.HostSideTestClassLoadHook( + value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded" + ) + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class + Compiled from "TinyFrameworkExceptionTester.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 3, attributes: 3 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester; + + public static int testException(); + descriptor: ()I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester + x: ldc #x // String testException + x: ldc #x // String ()I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: new #x // class java/lang/IllegalStateException + x: dup + x: ldc #x // String Inner exception + x: invokespecial #x // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V + x: athrow + x: astore_0 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Outer exception + x: aload_0 + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V + x: athrow + Exception table: + from to target type + 11 21 21 Class java/lang/Exception + StackMapTable: number_of_entries = 1 + frame_type = 85 /* same_locals_1_stack_item */ + stack = [ class java/lang/Exception ] + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 22 11 0 e Ljava/lang/Exception; +} +SourceFile: "TinyFrameworkExceptionTester.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.class + Compiled from "TinyFrameworkForTextPolicy.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy + super_class: #x // java/lang/Object + interfaces: 0, fields: 2, methods: 8, attributes: 2 + public int stub; + descriptor: I + flags: (0x0001) ACC_PUBLIC + + public int keep; + descriptor: I + flags: (0x0001) ACC_PUBLIC + + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy + x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: aload_0 + x: iconst_1 + x: putfield #x // Field stub:I + x: aload_0 + x: iconst_2 + x: putfield #x // Field keep:I + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy; + + public int addOne(int); + descriptor: (I)I + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy + x: ldc #x // String addOne + x: ldc #x // String (I)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: iload_1 + x: invokevirtual #x // Method addOneInner:(I)I + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy; + 11 6 1 value I + + public int addOneInner(int); + descriptor: (I)I + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy + x: ldc #x // String addOneInner + x: ldc #x // String (I)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy + x: ldc #x // String addOneInner + x: ldc #x // String (I)I + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: iload_1 + x: iconst_1 + x: iadd + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 26 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy; + 26 4 1 value I + + public int addTwo(int); + descriptor: (I)I + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy + x: ldc #x // String addTwo + x: ldc #x // String (I)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: iload_1 + x: iconst_2 + x: iadd + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy; + 11 4 1 value I + + public static int nativeAddThree(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy + x: ldc #x // String nativeAddThree + x: ldc #x // String (I)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: iload_0 + x: iconst_3 + x: iadd + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 4 0 value I + + public java.lang.String unsupportedMethod(); + descriptor: ()Ljava/lang/String; + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy + x: ldc #x // String unsupportedMethod + x: ldc #x // String ()Ljava/lang/String; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy + x: ldc #x // String unsupportedMethod + x: ldc #x // String ()Ljava/lang/String; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Unreachable + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + + public java.lang.String visibleButUsesUnsupportedMethod(); + descriptor: ()Ljava/lang/String; + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy + x: ldc #x // String visibleButUsesUnsupportedMethod + x: ldc #x // String ()Ljava/lang/String; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String; + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy; +} +SourceFile: "TinyFrameworkForTextPolicy.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class + Compiled from "TinyFrameworkNative.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 6, attributes: 3 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative; + + public static int nativeAddTwo(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=1, locals=1, args_size=1 + x: iload_0 + x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I + x: ireturn + + public static int nativeAddTwo_should_be_like_this(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative + x: ldc #x // String nativeAddTwo_should_be_like_this + x: ldc #x // String (I)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: iload_0 + x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 arg I + + public static long nativeLongPlus(long, long); + descriptor: (JJ)J + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=4, args_size=2 + x: lload_0 + x: lload_2 + x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J + x: lreturn + + public static long nativeLongPlus_should_be_like_this(long, long); + descriptor: (JJ)J + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=4, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative + x: ldc #x // String nativeLongPlus_should_be_like_this + x: ldc #x // String (JJ)J + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: lload_0 + x: lload_2 + x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J + x: lreturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 6 0 arg1 J + 11 6 2 arg2 J +} +SourceFile: "TinyFrameworkNative.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub + x: #x(#x=s#x) + android.hosttest.annotation.HostSideTestNativeSubstitutionClass( + value="TinyFrameworkNative_host" + ) +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.class + Compiled from "TinyFrameworkNative_host.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 4, attributes: 3 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host + x: ldc #x // String <init> + x: ldc #x // String ()V + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host; + + public static int nativeAddTwo(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host + x: ldc #x // String nativeAddTwo + x: ldc #x // String (I)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host + x: ldc #x // String nativeAddTwo + x: ldc #x // String (I)I + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: iload_0 + x: iconst_2 + x: iadd + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 26 4 0 arg I + + public static long nativeLongPlus(long, long); + descriptor: (JJ)J + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=4, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host + x: ldc #x // String nativeLongPlus + x: ldc #x // String (JJ)J + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host + x: ldc #x // String nativeLongPlus + x: ldc #x // String (JJ)J + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: lload_0 + x: lload_2 + x: ladd + x: lreturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 26 4 0 arg1 J + 26 4 2 arg2 J +} +SourceFile: "TinyFrameworkNative_host.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassKeep +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1.class + Compiled from "TinyFrameworkNestedClasses.java" +class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer> + minor version: 0 + major version: 61 + flags: (0x0020) ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 + super_class: #x // java/lang/Object + interfaces: 1, fields: 1, methods: 4, attributes: 6 + final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0; + descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC + + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses); + descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V + flags: (0x0000) + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 + x: ldc #x // String <init> + x: ldc #x // String (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: aload_1 + x: putfield #x // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1; + 11 10 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + + public java.lang.Integer get(); + descriptor: ()Ljava/lang/Integer; + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Integer; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Integer; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: iconst_1 + x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1; + + public java.lang.Object get(); + descriptor: ()Ljava/lang/Object; + flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Object; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Object; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: aload_0 + x: invokevirtual #x // Method get:()Ljava/lang/Integer; + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1; +} +InnerClasses: + #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 +EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses +Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>; +SourceFile: "TinyFrameworkNestedClasses.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2.class + Compiled from "TinyFrameworkNestedClasses.java" +class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer> + minor version: 0 + major version: 61 + flags: (0x0020) ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 + super_class: #x // java/lang/Object + interfaces: 1, fields: 0, methods: 4, attributes: 6 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2(); + descriptor: ()V + flags: (0x0000) + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2; + + public java.lang.Integer get(); + descriptor: ()Ljava/lang/Integer; + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Integer; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Integer; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: iconst_2 + x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2; + + public java.lang.Object get(); + descriptor: ()Ljava/lang/Object; + flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Object; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Object; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: aload_0 + x: invokevirtual #x // Method get:()Ljava/lang/Integer; + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2; +} +InnerClasses: + #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 +EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses +Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>; +SourceFile: "TinyFrameworkNestedClasses.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3.class + Compiled from "TinyFrameworkNestedClasses.java" +class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer> + minor version: 0 + major version: 61 + flags: (0x0020) ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 + super_class: #x // java/lang/Object + interfaces: 1, fields: 1, methods: 4, attributes: 6 + final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0; + descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC + + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses); + descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V + flags: (0x0000) + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 + x: ldc #x // String <init> + x: ldc #x // String (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: aload_1 + x: putfield #x // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3; + 11 10 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + + public java.lang.Integer get(); + descriptor: ()Ljava/lang/Integer; + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Integer; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Integer; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: iconst_3 + x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3; + + public java.lang.Object get(); + descriptor: ()Ljava/lang/Object; + flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Object; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Object; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: aload_0 + x: invokevirtual #x // Method get:()Ljava/lang/Integer; + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3; +} +InnerClasses: + #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 +EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier +Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>; +SourceFile: "TinyFrameworkNestedClasses.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4.class + Compiled from "TinyFrameworkNestedClasses.java" +class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer> + minor version: 0 + major version: 61 + flags: (0x0020) ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 + super_class: #x // java/lang/Object + interfaces: 1, fields: 0, methods: 4, attributes: 6 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4(); + descriptor: ()V + flags: (0x0000) + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4; + + public java.lang.Integer get(); + descriptor: ()Ljava/lang/Integer; + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Integer; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Integer; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: iconst_4 + x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4; + + public java.lang.Object get(); + descriptor: ()Ljava/lang/Object; + flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Object; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Object; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: aload_0 + x: invokevirtual #x // Method get:()Ljava/lang/Integer; + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4; +} +InnerClasses: + #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 +EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier_static +Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>; +SourceFile: "TinyFrameworkNestedClasses.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass.class + Compiled from "TinyFrameworkNestedClasses.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 4 + public int value; + descriptor: I + flags: (0x0001) ACC_PUBLIC + + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass(int); + descriptor: (I)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass + x: ldc #x // String <init> + x: ldc #x // String (I)V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: aload_0 + x: iload_1 + x: putfield #x // Field value:I + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass; + 11 10 1 x I +} +InnerClasses: + public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +SourceFile: "TinyFrameworkNestedClasses.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class + Compiled from "TinyFrameworkNestedClasses.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass + super_class: #x // java/lang/Object + interfaces: 0, fields: 2, methods: 2, attributes: 5 + public int value; + descriptor: I + flags: (0x0001) ACC_PUBLIC + + final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0; + descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC + + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses); + descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass + x: ldc #x // String <init> + x: ldc #x // String (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: aload_1 + x: putfield #x // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: aload_0 + x: iconst_5 + x: putfield #x // Field value:I + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass; + 11 15 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; +} +InnerClasses: + public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +SourceFile: "TinyFrameworkNestedClasses.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1.class + Compiled from "TinyFrameworkNestedClasses.java" +class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer> + minor version: 0 + major version: 61 + flags: (0x0020) ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 + super_class: #x // java/lang/Object + interfaces: 1, fields: 0, methods: 4, attributes: 6 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1(); + descriptor: ()V + flags: (0x0000) + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1; + + public java.lang.Integer get(); + descriptor: ()Ljava/lang/Integer; + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Integer; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Integer; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: bipush 7 + x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 26 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1; + + public java.lang.Object get(); + descriptor: ()Ljava/lang/Object; + flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Object; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 + x: ldc #x // String get + x: ldc #x // String ()Ljava/lang/Object; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker; + x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class; + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V + x: aload_0 + x: invokevirtual #x // Method get:()Ljava/lang/Integer; + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1; +} +InnerClasses: + public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 +EnclosingMethod: #x.#x // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass.getSupplier_static +Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>; +SourceFile: "TinyFrameworkNestedClasses.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class + Compiled from "TinyFrameworkNestedClasses.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 3, attributes: 5 + public int value; + descriptor: I + flags: (0x0001) ACC_PUBLIC + + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: aload_0 + x: bipush 6 + x: putfield #x // Field value:I + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 11 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass; + + public static java.util.function.Supplier<java.lang.Integer> getSupplier_static(); + descriptor: ()Ljava/util/function/Supplier; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass + x: ldc #x // String getSupplier_static + x: ldc #x // String ()Ljava/util/function/Supplier; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 + x: dup + x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1."<init>":()V + x: areturn + LineNumberTable: + Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; +} +InnerClasses: + public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 +SourceFile: "TinyFrameworkNestedClasses.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class + Compiled from "TinyFrameworkNestedClasses.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass extends com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass + super_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass + interfaces: 0, fields: 0, methods: 2, attributes: 4 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass(int); + descriptor: (I)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass + x: ldc #x // String <init> + x: ldc #x // String (I)V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: iload_1 + x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass."<init>":(I)V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass; + 11 6 1 x I +} +InnerClasses: + public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + public static #x= #x of #x; // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +SourceFile: "TinyFrameworkNestedClasses.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class + Compiled from "TinyFrameworkNestedClasses.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + super_class: #x // java/lang/Object + interfaces: 0, fields: 2, methods: 4, attributes: 5 + public final java.util.function.Supplier<java.lang.Integer> mSupplier; + descriptor: Ljava/util/function/Supplier; + flags: (0x0011) ACC_PUBLIC, ACC_FINAL + Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + + public static final java.util.function.Supplier<java.lang.Integer> sSupplier; + descriptor: Ljava/util/function/Supplier; + flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL + Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: aload_0 + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 + x: dup + x: aload_0 + x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V + x: putfield #x // Field mSupplier:Ljava/util/function/Supplier; + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 17 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + + public java.util.function.Supplier<java.lang.Integer> getSupplier(); + descriptor: ()Ljava/util/function/Supplier; + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + x: ldc #x // String getSupplier + x: ldc #x // String ()Ljava/util/function/Supplier; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 + x: dup + x: aload_0 + x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 9 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + + public static java.util.function.Supplier<java.lang.Integer> getSupplier_static(); + descriptor: ()Ljava/util/function/Supplier; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + x: ldc #x // String getSupplier_static + x: ldc #x // String ()Ljava/util/function/Supplier; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 + x: dup + x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4."<init>":()V + x: areturn + LineNumberTable: + Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + + static {}; + descriptor: ()V + flags: (0x0008) ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + x: ldc #x // String <clinit> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 + x: dup + x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2."<init>":()V + x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier; + x: return + LineNumberTable: +} +InnerClasses: + #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 + #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 + #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 + #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 + public static #x= #x of #x; // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses + #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 +SourceFile: "TinyFrameworkNestedClasses.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass +RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestWholeClassStub +NestMembers: + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 + com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 diff --git a/tools/hoststubgen/scripts/run-all-tests.sh b/tools/hoststubgen/scripts/run-all-tests.sh index 6bc0ddb1a8dc..7600942c99e6 100755 --- a/tools/hoststubgen/scripts/run-all-tests.sh +++ b/tools/hoststubgen/scripts/run-all-tests.sh @@ -34,6 +34,7 @@ run ./hoststubgen/test-tiny-framework/diff-and-update-golden.sh run ./hoststubgen/test-framework/run-test-without-atest.sh run ./hoststubgen/test-tiny-framework/run-test-manually.sh +run atest tiny-framework-dump-test run ./scripts/build-framework-hostside-jars-and-extract.sh # This script is already broken on goog/master diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt index cbbf91b49ded..758de4dfccf8 100644 --- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt +++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt @@ -131,7 +131,7 @@ class EnforcePermissionHelperDetector : Detector(), SourceCodeScanner { priority = 6, severity = Severity.ERROR, implementation = Implementation( - EnforcePermissionDetector::class.java, + EnforcePermissionHelperDetector::class.java, EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES) ) ) |