diff options
172 files changed, 3447 insertions, 951 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 2ce3221e56cf..302168d845fa 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -1856,6 +1856,41 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } +// SettingsTheme Lib +aconfig_declarations { + name: "aconfig_settings_theme_flags", + package: "com.android.settingslib.widget.theme.flags", + container: "system", + exportable: true, + srcs: [ + "packages/SettingsLib/SettingsTheme/aconfig/settingstheme.aconfig", + ], +} + +java_aconfig_library { + name: "aconfig_settingstheme_exported_flags_java_lib", + aconfig_declarations: "aconfig_settings_theme_flags", + defaults: ["framework-minus-apex-aconfig-java-defaults"], + mode: "exported", + min_sdk_version: "21", + apex_available: [ + "//apex_available:platform", + "com.android.adservices", + "com.android.cellbroadcast", + "com.android.devicelock", + "com.android.extservices", + "com.android.healthfitness", + "com.android.mediaprovider", + "com.android.permission", + ], +} + +java_aconfig_library { + name: "aconfig_settingstheme_flags_java_lib", + aconfig_declarations: "aconfig_settings_theme_flags", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} + // Quick Access Wallet aconfig_declarations { name: "android.service.quickaccesswallet.flags-aconfig", diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 4a78d01783f8..8fa2362139a1 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -273,4 +273,7 @@ interface INotificationManager void setAssistantAdjustmentKeyTypeState(int type, boolean enabled); String[] getTypeAdjustmentDeniedPackages(); void setTypeAdjustmentForPackageState(String pkg, boolean enabled); + + // TODO: b/389918945 - Remove once nm_binder_perf flags are going to Nextfood. + void incrementCounter(String metricId); } diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index e5d80de24f2b..05b3316a5133 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -665,8 +665,10 @@ public class NotificationManager { private final InstantSource mClock; private final RateLimiter mUpdateRateLimiter = new RateLimiter("notify (update)", + "notifications.value_client_throttled_notify_update", MAX_NOTIFICATION_UPDATE_RATE); private final RateLimiter mUnnecessaryCancelRateLimiter = new RateLimiter("cancel (dupe)", + "notifications.value_client_throttled_cancel_duplicate", MAX_NOTIFICATION_UNNECESSARY_CANCEL_RATE); // Value is KNOWN_STATUS_ENQUEUED/_CANCELLED private final LruCache<NotificationKey, Integer> mKnownNotifications = new LruCache<>(100); @@ -848,19 +850,21 @@ public class NotificationManager { /** Helper class to rate-limit Binder calls. */ private class RateLimiter { - private static final Duration RATE_LIMITER_LOG_INTERVAL = Duration.ofSeconds(5); + private static final Duration RATE_LIMITER_LOG_INTERVAL = Duration.ofSeconds(1); private final RateEstimator mInputRateEstimator; private final RateEstimator mOutputRateEstimator; private final String mName; + private final String mCounterName; private final float mLimitRate; private Instant mLogSilencedUntil; - private RateLimiter(String name, float limitRate) { + private RateLimiter(String name, String counterName, float limitRate) { mInputRateEstimator = new RateEstimator(); mOutputRateEstimator = new RateEstimator(); mName = name; + mCounterName = counterName; mLimitRate = limitRate; } @@ -880,6 +884,14 @@ public class NotificationManager { return; } + if (Flags.nmBinderPerfLogNmThrottling()) { + try { + service().incrementCounter(mCounterName); + } catch (RemoteException e) { + Slog.w(TAG, "Ignoring error while trying to log " + mCounterName, e); + } + } + long nowMillis = now.toEpochMilli(); Slog.w(TAG, TextUtils.formatSimple( "Shedding %s of %s, rate limit (%s) exceeded: input %s, output would be %s", diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig index edd17e8bb552..914ca73f1ce4 100644 --- a/core/java/android/app/notification.aconfig +++ b/core/java/android/app/notification.aconfig @@ -295,6 +295,16 @@ flag { } flag { + name: "nm_binder_perf_log_nm_throttling" + namespace: "systemui" + description: "Log throttled operations (notify, cancel) to statsd. This flag will NOT be pushed past Trunkfood." + bug: "389918945" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "no_sbnholder" namespace: "systemui" description: "removes sbnholder from NLS" diff --git a/core/java/android/companion/AssociationInfo.java b/core/java/android/companion/AssociationInfo.java index 2f161150a89b..ceafce2bdbb7 100644 --- a/core/java/android/companion/AssociationInfo.java +++ b/core/java/android/companion/AssociationInfo.java @@ -287,8 +287,8 @@ public final class AssociationInfo implements Parcelable { /** * Get the device icon of the associated device. The device icon represents the device type. * - * @return the device icon, or {@code null} if no device icon has been set for the - * associated device. + * @return the device icon with size 24dp x 24dp. + * If the associated device has no icon set, it returns {@code null}. * * @see AssociationRequest.Builder#setDeviceIcon(Icon) */ @@ -377,6 +377,7 @@ public final class AssociationInfo implements Parcelable { if (this == o) return true; if (!(o instanceof AssociationInfo)) return false; final AssociationInfo that = (AssociationInfo) o; + return mId == that.mId && mUserId == that.mUserId && mSelfManaged == that.mSelfManaged @@ -391,11 +392,17 @@ public final class AssociationInfo implements Parcelable { && Objects.equals(mDeviceProfile, that.mDeviceProfile) && Objects.equals(mAssociatedDevice, that.mAssociatedDevice) && mSystemDataSyncFlags == that.mSystemDataSyncFlags - && (mDeviceIcon == null ? that.mDeviceIcon == null - : mDeviceIcon.sameAs(that.mDeviceIcon)) + && isSameIcon(mDeviceIcon, that.mDeviceIcon) && Objects.equals(mDeviceId, that.mDeviceId); } + private boolean isSameIcon(Icon iconA, Icon iconB) { + // Because we've already rescaled and converted both icons to bitmaps, + // we can now directly compare them by bitmap. + return (iconA == null && iconB == null) + || (iconA != null && iconB != null && iconA.getBitmap().sameAs(iconB.getBitmap())); + } + @Override public int hashCode() { return Objects.hash(mId, mUserId, mPackageName, mDeviceMacAddress, mDisplayName, @@ -425,7 +432,7 @@ public final class AssociationInfo implements Parcelable { dest.writeLong(mTimeApprovedMs); dest.writeLong(mLastTimeConnectedMs); dest.writeInt(mSystemDataSyncFlags); - if (mDeviceIcon != null) { + if (Flags.associationDeviceIcon() && mDeviceIcon != null) { dest.writeInt(1); mDeviceIcon.writeToParcel(dest, flags); } else { @@ -455,7 +462,8 @@ public final class AssociationInfo implements Parcelable { mTimeApprovedMs = in.readLong(); mLastTimeConnectedMs = in.readLong(); mSystemDataSyncFlags = in.readInt(); - if (in.readInt() == 1) { + int deviceIcon = in.readInt(); + if (Flags.associationDeviceIcon() && deviceIcon == 1) { mDeviceIcon = Icon.CREATOR.createFromParcel(in); } else { mDeviceIcon = null; diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java index 32cbf326c923..a098a6067491 100644 --- a/core/java/android/companion/AssociationRequest.java +++ b/core/java/android/companion/AssociationRequest.java @@ -385,6 +385,10 @@ public final class AssociationRequest implements Parcelable { public void setAssociatedDevice(AssociatedDevice associatedDevice) { mAssociatedDevice = associatedDevice; } + /** @hide */ + public void setDeviceIcon(Icon deviceIcon) { + mDeviceIcon = deviceIcon; + } /** @hide */ @NonNull @@ -492,9 +496,10 @@ public final class AssociationRequest implements Parcelable { /** * Set the device icon for the self-managed device and to display the icon in the * self-managed association dialog. + * <p>The given device icon will be resized to 24dp x 24dp. * - * @throws IllegalArgumentException if the icon is not exactly 24dp by 24dp - * or if it is {@link Icon#TYPE_URI} or {@link Icon#TYPE_URI_ADAPTIVE_BITMAP}. + * @throws IllegalArgumentException if the icon is + * {@link Icon#TYPE_URI} or {@link Icon#TYPE_URI_ADAPTIVE_BITMAP}. * @see #setSelfManaged(boolean) */ @NonNull diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java index a96ba11eb482..566e78a8de35 100644 --- a/core/java/android/companion/CompanionDeviceManager.java +++ b/core/java/android/companion/CompanionDeviceManager.java @@ -23,7 +23,6 @@ import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH; import static android.graphics.drawable.Icon.TYPE_URI; import static android.graphics.drawable.Icon.TYPE_URI_ADAPTIVE_BITMAP; - import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; import android.annotation.IntDef; @@ -52,10 +51,10 @@ import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager; import android.graphics.Bitmap; +import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; -import android.graphics.drawable.VectorDrawable; import android.net.MacAddress; import android.os.Binder; import android.os.Handler; @@ -110,6 +109,7 @@ import java.util.function.Consumer; @RequiresFeature(PackageManager.FEATURE_COMPANION_DEVICE_SETUP) public final class CompanionDeviceManager { private static final String TAG = "CDM_CompanionDeviceManager"; + private static final int ICON_TARGET_SIZE = 24; /** @hide */ @IntDef(prefix = {"RESULT_"}, value = { @@ -474,10 +474,8 @@ public final class CompanionDeviceManager { if (Flags.associationDeviceIcon()) { final Icon deviceIcon = request.getDeviceIcon(); - - if (deviceIcon != null && !isValidIcon(deviceIcon, mContext)) { - throw new IllegalArgumentException("The size of the device icon must be " - + "24dp x 24dp to ensure proper display"); + if (deviceIcon != null) { + request.setDeviceIcon(scaleIcon(deviceIcon, mContext)); } } @@ -547,10 +545,8 @@ public final class CompanionDeviceManager { if (Flags.associationDeviceIcon()) { final Icon deviceIcon = request.getDeviceIcon(); - - if (deviceIcon != null && !isValidIcon(deviceIcon, mContext)) { - throw new IllegalArgumentException("The size of the device icon must be " - + "24dp x 24dp to ensure proper display"); + if (deviceIcon != null) { + request.setDeviceIcon(scaleIcon(deviceIcon, mContext)); } } @@ -2024,33 +2020,26 @@ public final class CompanionDeviceManager { } } - private boolean isValidIcon(Icon icon, Context context) { + private Icon scaleIcon(Icon icon, Context context) { + if (icon == null) return null; if (icon.getType() == TYPE_URI_ADAPTIVE_BITMAP || icon.getType() == TYPE_URI) { throw new IllegalArgumentException("The URI based Icon is not supported."); } - Drawable drawable = icon.loadDrawable(context); - float density = context.getResources().getDisplayMetrics().density; + Bitmap bitmap; + Drawable drawable = icon.loadDrawable(context); if (drawable instanceof BitmapDrawable) { - Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); - - float widthDp = bitmap.getWidth() / density; - float heightDp = bitmap.getHeight() / density; - - if (widthDp != 24 || heightDp != 24) { - return false; - } - } else if (drawable instanceof VectorDrawable) { - VectorDrawable vectorDrawable = (VectorDrawable) drawable; - float widthDp = vectorDrawable.getIntrinsicWidth() / density; - float heightDp = vectorDrawable.getIntrinsicHeight() / density; - - if (widthDp != 24 || heightDp != 24) { - return false; - } + bitmap = Bitmap.createScaledBitmap( + ((BitmapDrawable) drawable).getBitmap(), ICON_TARGET_SIZE, ICON_TARGET_SIZE, + false); } else { - throw new IllegalArgumentException("The format of the device icon is unsupported."); + bitmap = Bitmap.createBitmap(context.getResources().getDisplayMetrics(), + ICON_TARGET_SIZE, ICON_TARGET_SIZE, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); } - return true; + + return Icon.createWithBitmap(bitmap); } } diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 875b9098843f..4aa74621bd62 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -2831,11 +2831,9 @@ public final class Parcel { } } - private void resetSquashingState() { + private void resetSqaushingState() { if (mAllowSquashing) { - String error = "allowSquashing wasn't restored."; - Slog.wtf(TAG, error); - throw new BadParcelableException(error); + Slog.wtf(TAG, "allowSquashing wasn't restored."); } mWrittenSquashableParcelables = null; mReadSquashableParcelables = null; @@ -2952,11 +2950,9 @@ public final class Parcel { for (int i = 0; i < mReadSquashableParcelables.size(); i++) { sb.append(mReadSquashableParcelables.keyAt(i)).append(' '); } - String error = "Map doesn't contain offset " + Slog.wtfStack(TAG, "Map doesn't contain offset " + firstAbsolutePos - + " : contains=" + sb.toString(); - Slog.wtfStack(TAG, error); - throw new BadParcelableException(error); + + " : contains=" + sb.toString()); } return (T) p; } @@ -5509,7 +5505,7 @@ public final class Parcel { private void freeBuffer() { mFlags = 0; - resetSquashingState(); + resetSqaushingState(); if (mOwnsNativeParcelObject) { nativeFreeBuffer(mNativePtr); } @@ -5517,7 +5513,7 @@ public final class Parcel { } private void destroy() { - resetSquashingState(); + resetSqaushingState(); if (mNativePtr != 0) { if (mOwnsNativeParcelObject) { nativeDestroy(mNativePtr); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 73d1e1701eec..a22333bd1812 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9314,6 +9314,16 @@ public final class Settings { "accessibility_autoclick_cursor_area_size"; /** + * Setting that specifies whether minor cursor movement will be ignored when + * {@link #ACCESSIBILITY_AUTOCLICK_ENABLED} is set. + * + * @see #ACCESSIBILITY_AUTOCLICK_ENABLED + * @hide + */ + public static final String ACCESSIBILITY_AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT = + "accessibility_autoclick_ignore_minor_cursor_movement"; + + /** * Whether or not larger size icons are used for the pointer of mouse/trackpad for * accessibility. * (0 = false, 1 = true) diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig index a5586227cbb3..792e6ff52d01 100644 --- a/core/java/android/security/flags.aconfig +++ b/core/java/android/security/flags.aconfig @@ -43,7 +43,7 @@ flag { flag { name: "secure_array_zeroization" - namespace: "platform_security" + namespace: "security" description: "Enable secure array zeroization" bug: "320392352" metadata { diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java index 01de54354a04..e1dc6f6d642b 100644 --- a/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java +++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java @@ -131,7 +131,7 @@ class QuickAccessWalletServiceInfo { == PackageManager.PERMISSION_GRANTED) { user = roleManager.getActiveUserForRole(RoleManager.ROLE_WALLET); if (user == null) { - return new Pair<>(null, user.getIdentifier()); + return new Pair<>(null, UserHandle.myUserId()); } } List<String> roleHolders = roleManager.getRoleHoldersAsUser(RoleManager.ROLE_WALLET, diff --git a/core/java/android/timezone/MobileCountries.java b/core/java/android/timezone/MobileCountries.java new file mode 100644 index 000000000000..19ae60880d20 --- /dev/null +++ b/core/java/android/timezone/MobileCountries.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2025 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.timezone; + +import android.annotation.NonNull; + +import java.util.Objects; +import java.util.Set; + +/** + * Information about a telephony network. + * + * @hide + */ +public final class MobileCountries { + + @NonNull + private final com.android.i18n.timezone.MobileCountries mDelegate; + + MobileCountries(@NonNull com.android.i18n.timezone.MobileCountries delegate) { + mDelegate = Objects.requireNonNull(delegate); + } + + /** + * Returns the Mobile Country Code of the network. + */ + @NonNull + public String getMcc() { + return mDelegate.getMcc(); + } + + /** + * Returns the Mobile Country Code of the network. + */ + @NonNull + public Set<String> getCountryIsoCodes() { + return mDelegate.getCountryIsoCodes(); + } + + /** + * Returns the country in which the network operates as an ISO 3166 alpha-2 (lower case). + */ + @NonNull + public String getDefaultCountryIsoCode() { + return mDelegate.getDefaultCountryIsoCode(); + } + + @Override + public String toString() { + return "MobileCountries{" + + "mDelegate=" + mDelegate + + '}'; + } +} diff --git a/core/java/android/timezone/TelephonyNetworkFinder.java b/core/java/android/timezone/TelephonyNetworkFinder.java index fb4a19b9dcac..eb50fc24d9ad 100644 --- a/core/java/android/timezone/TelephonyNetworkFinder.java +++ b/core/java/android/timezone/TelephonyNetworkFinder.java @@ -19,7 +19,6 @@ package android.timezone; import android.annotation.NonNull; import android.annotation.Nullable; -import com.android.i18n.timezone.MobileCountries; import com.android.icu.Flags; import java.util.Objects; @@ -59,11 +58,13 @@ public final class TelephonyNetworkFinder { */ @Nullable public MobileCountries findCountriesByMcc(@NonNull String mcc) { - Objects.requireNonNull(mcc); - if (!Flags.telephonyLookupMccExtension()) { return null; } - return mDelegate.findCountriesByMcc(mcc); + Objects.requireNonNull(mcc); + + com.android.i18n.timezone.MobileCountries countriesByMcc = + mDelegate.findCountriesByMcc(mcc); + return countriesByMcc != null ? new MobileCountries(countriesByMcc) : null; } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index d88b6d642ee6..7206906658ff 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -28365,10 +28365,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (android.os.Flags.adpfMeasureDuringInputEventBoost()) { final boolean notifyRenderer = hasExpensiveMeasuresDuringInputEvent(); if (notifyRenderer) { - Trace.traceBegin(Trace.TRACE_TAG_VIEW, - "CPU_LOAD_UP: " + "hasExpensiveMeasuresDuringInputEvent"); - getViewRootImpl().notifyRendererOfExpensiveFrame(); - Trace.traceEnd(Trace.TRACE_TAG_VIEW); + getViewRootImpl().notifyRendererOfExpensiveFrame( + "ADPF_SendHint: hasExpensiveMeasuresDuringInputEvent"); } } // measure ourselves, this should set the measured dimension flag back diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 64e7becb1ed4..cd8a85a66c1a 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2968,6 +2968,20 @@ public final class ViewRootImpl implements ViewParent, } } + /** + * Same as notifyRendererOfExpensiveFrame(), but adding {@code reason} for tracing. + * + * @hide + */ + public void notifyRendererOfExpensiveFrame(String reason) { + Trace.traceBegin(Trace.TRACE_TAG_VIEW, reason); + try { + notifyRendererOfExpensiveFrame(); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIEW); + } + } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) void scheduleTraversals() { if (!mTraversalScheduled) { diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 64277b14098d..d267c9451d1a 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -160,6 +160,9 @@ public final class AccessibilityManager { /** @hide */ public static final int AUTOCLICK_CURSOR_AREA_INCREMENT_SIZE = 20; + /** @hide */ + public static final boolean AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT_DEFAULT = false; + /** * Activity action: Launch UI to manage which accessibility service or feature is assigned * to the navigation bar Accessibility button. diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java index ed6ec32fca25..3cc0042f2bcc 100644 --- a/core/java/android/widget/CompoundButton.java +++ b/core/java/android/widget/CompoundButton.java @@ -16,6 +16,8 @@ package android.widget; +import static android.view.accessibility.Flags.triStateChecked; + import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; @@ -209,6 +211,10 @@ public abstract class CompoundButton extends Button implements Checkable { mCheckedFromResource = false; mChecked = checked; refreshDrawableState(); + if (triStateChecked()) { + notifyViewAccessibilityStateChangedIfNeeded( + AccessibilityEvent.CONTENT_CHANGE_TYPE_CHECKED); + } // Avoid infinite recursions if setChecked() is called from a listener if (mBroadcasting) { @@ -490,7 +496,12 @@ public abstract class CompoundButton extends Button implements Checkable { public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfoInternal(info); info.setCheckable(true); - info.setChecked(mChecked); + if (triStateChecked()) { + info.setChecked(mChecked ? AccessibilityNodeInfo.CHECKED_STATE_TRUE : + AccessibilityNodeInfo.CHECKED_STATE_FALSE); + } else { + info.setChecked(mChecked); + } } @Override diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java index 158b526cb1a0..928fa8ca35cf 100644 --- a/core/java/com/android/internal/jank/Cuj.java +++ b/core/java/com/android/internal/jank/Cuj.java @@ -265,8 +265,17 @@ public class Cuj { */ public static final int CUJ_LAUNCHER_OVERVIEW_TASK_DISMISS = 121; + /** + * Track closing task in Desktop Windowing. + * + * <p> Tracking begins when the CloseDesktopTaskTransitionHandler in Launcher starts + * animating the task closure. This is triggered when the close button in the app header is + * clicked on a desktop window. </p> + */ + public static final int CUJ_DESKTOP_MODE_CLOSE_TASK = 122; + // When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE. - @VisibleForTesting static final int LAST_CUJ = CUJ_LAUNCHER_OVERVIEW_TASK_DISMISS; + @VisibleForTesting static final int LAST_CUJ = CUJ_DESKTOP_MODE_CLOSE_TASK; /** @hide */ @IntDef({ @@ -379,7 +388,8 @@ public class Cuj { CUJ_DESKTOP_MODE_SNAP_RESIZE, CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW, CUJ_DESKTOP_MODE_ENTER_FROM_OVERVIEW_MENU, - CUJ_LAUNCHER_OVERVIEW_TASK_DISMISS + CUJ_LAUNCHER_OVERVIEW_TASK_DISMISS, + CUJ_DESKTOP_MODE_CLOSE_TASK }) @Retention(RetentionPolicy.SOURCE) public @interface CujType {} @@ -503,6 +513,7 @@ public class Cuj { CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_UNMAXIMIZE_WINDOW; CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_ENTER_FROM_OVERVIEW_MENU] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_ENTER_FROM_OVERVIEW_MENU; CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_OVERVIEW_TASK_DISMISS] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OVERVIEW_TASK_DISMISS; + CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_CLOSE_TASK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_CLOSE_TASK; } private Cuj() { @@ -741,6 +752,8 @@ public class Cuj { return "DESKTOP_MODE_ENTER_FROM_OVERVIEW_MENU"; case CUJ_LAUNCHER_OVERVIEW_TASK_DISMISS: return "LAUNCHER_OVERVIEW_TASK_DISMISS"; + case CUJ_DESKTOP_MODE_CLOSE_TASK: + return "DESKTOP_MODE_CLOSE_TASK"; } return "UNKNOWN"; } diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto index 5d0b340ac839..69c812c6fb41 100644 --- a/core/proto/android/providers/settings/secure.proto +++ b/core/proto/android/providers/settings/secure.proto @@ -109,6 +109,7 @@ message SecureSettingsProto { optional SettingProto em_value = 61 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Settings for accessibility autoclick optional SettingProto autoclick_cursor_area_size = 62 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto autoclick_ignore_minor_cursor_movement = 63 [ (android.privacy).dest = DEST_AUTOMATIC ]; } optional Accessibility accessibility = 2; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 73279700ecb1..aad8f8a156b5 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -8324,16 +8324,15 @@ <!-- Allows an application to perform actions on behalf of users inside of applications. - <p>This permission is currently only granted to preinstalled / system apps having the - {@link android.app.role.ASSISTANT} role. + <p>This permission is currently only granted to privileged system apps. <p>Apps contributing app functions can opt to disallow callers with this permission, limiting to only callers with {@link android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} instead. - <p>Protection level: internal|role + <p>Protection level: internal|privileged @FlaggedApi(android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER) --> <permission android:name="android.permission.EXECUTE_APP_FUNCTIONS" android:featureFlag="android.app.appfunctions.flags.enable_app_function_manager" - android:protectionLevel="internal|role" /> + android:protectionLevel="internal|privileged" /> <!-- Allows an application to display its suggestions using the autofill framework. <p>For now, this permission is only granted to the Browser application. diff --git a/core/tests/coretests/src/android/app/NotificationManagerTest.java b/core/tests/coretests/src/android/app/NotificationManagerTest.java index 18ba6a16bf72..a201f1fe6d89 100644 --- a/core/tests/coretests/src/android/app/NotificationManagerTest.java +++ b/core/tests/coretests/src/android/app/NotificationManagerTest.java @@ -263,6 +263,38 @@ public class NotificationManagerTest { } @Test + @EnableFlags({Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY, + Flags.FLAG_NM_BINDER_PERF_LOG_NM_THROTTLING}) + public void notify_rapidUpdate_logsOncePerSecond() throws Exception { + Notification n = exampleNotification(); + + for (int i = 0; i < 650; i++) { + mNotificationManager.notify(1, n); + mClock.advanceByMillis(10); + } + + // Runs for a total of 6.5 seconds, so should log once (when RateEstimator catches up) + 6 + // more times (after 1 second each). + verify(mNotificationManager.mBackendService, times(7)).incrementCounter( + eq("notifications.value_client_throttled_notify_update")); + } + + @Test + @EnableFlags({Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY, + Flags.FLAG_NM_BINDER_PERF_LOG_NM_THROTTLING}) + public void cancel_unnecessaryAndRapid_logsOncePerSecond() throws Exception { + for (int i = 0; i < 650; i++) { + mNotificationManager.cancel(1); + mClock.advanceByMillis(10); + } + + // Runs for a total of 6.5 seconds, so should log once (when RateEstimator catches up) + 6 + // more times (after 1 second each). + verify(mNotificationManager.mBackendService, times(7)).incrementCounter( + eq("notifications.value_client_throttled_cancel_duplicate")); + } + + @Test @EnableFlags(Flags.FLAG_NM_BINDER_PERF_CACHE_CHANNELS) public void getNotificationChannel_cachedUntilInvalidated() throws Exception { // Invalidate the cache first because the cache won't do anything until then diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index 4c7e47769613..d0d1721115cb 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -73,6 +73,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import android.os.OperationCanceledException; import android.os.RemoteException; import android.os.SystemProperties; import android.util.ArrayMap; @@ -1106,7 +1107,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen void onTaskFragmentError(@NonNull WindowContainerTransaction wct, @Nullable IBinder errorCallbackToken, @Nullable TaskFragmentInfo taskFragmentInfo, @TaskFragmentOperation.OperationType int opType, @NonNull Throwable exception) { - Log.e(TAG, "onTaskFragmentError=" + exception.getMessage()); + if (exception instanceof OperationCanceledException) { + // This is a non-fatal error and the operation just canceled. + Log.i(TAG, "operation canceled:" + exception.getMessage()); + } else { + Log.e(TAG, "onTaskFragmentError=" + exception.getMessage(), exception); + } switch (opType) { case OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: case OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: { diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig index b10b099c970b..e4210261a9fc 100644 --- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig +++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig @@ -134,6 +134,16 @@ flag { } flag { + name: "enable_recents_bookend_transition" + namespace: "multitasking" + description: "Use a finish-transition to clean up recents instead of the finish-WCT" + bug: "346588978" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "bubble_view_info_executors" namespace: "multitasking" description: "Use executors to inflate bubble views" diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt index 90ea7d35015e..dd387b382dc6 100644 --- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt @@ -51,6 +51,7 @@ import com.android.wm.shell.shared.bubbles.BubbleBarUpdate import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit +import com.android.wm.shell.taskview.TaskViewRepository import com.android.wm.shell.taskview.TaskViewTransitions import com.android.wm.shell.transition.Transitions import com.google.common.truth.Truth.assertThat @@ -282,6 +283,7 @@ class BubbleControllerBubbleBarTest { mainExecutor, mock<Handler>(), bgExecutor, + mock<TaskViewRepository>(), mock<TaskViewTransitions>(), mock<Transitions>(), SyncTransactionQueue(TransactionPool(), mainExecutor), diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskTest.kt index a83327bbadee..f1ba0423b422 100644 --- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskTest.kt +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskTest.kt @@ -49,6 +49,7 @@ import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.taskview.TaskView +import com.android.wm.shell.taskview.TaskViewRepository import com.android.wm.shell.taskview.TaskViewTransitions import com.android.wm.shell.transition.Transitions import com.google.common.truth.Truth.assertThat @@ -155,6 +156,7 @@ class BubbleViewInfoTaskTest { mainExecutor, mock<Handler>(), bgExecutor, + mock<TaskViewRepository>(), mock<TaskViewTransitions>(), mock<Transitions>(), SyncTransactionQueue(TransactionPool(), mainExecutor), diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/FakeBubbleTaskViewFactory.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/FakeBubbleTaskViewFactory.kt index 42b66aa29bfc..896f2ee5dd8d 100644 --- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/FakeBubbleTaskViewFactory.kt +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/FakeBubbleTaskViewFactory.kt @@ -20,6 +20,7 @@ import android.app.ActivityManager import android.content.Context import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.taskview.TaskView +import com.android.wm.shell.taskview.TaskViewController import com.android.wm.shell.taskview.TaskViewTaskController import org.mockito.kotlin.mock import org.mockito.kotlin.whenever @@ -33,7 +34,7 @@ class FakeBubbleTaskViewFactory( ) : BubbleTaskViewFactory { override fun create(): BubbleTaskView { val taskViewTaskController = mock<TaskViewTaskController>() - val taskView = TaskView(context, taskViewTaskController) + val taskView = TaskView(context, mock<TaskViewController>(), taskViewTaskController) val taskInfo = mock<ActivityManager.RunningTaskInfo>() whenever(taskViewTaskController.taskInfo).thenReturn(taskInfo) return BubbleTaskView(taskView, mainExecutor) diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt index 9e58b5be9d0d..d3cfbd00c4a3 100644 --- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt @@ -47,6 +47,7 @@ import com.android.wm.shell.bubbles.FakeBubbleExpandedViewManager import com.android.wm.shell.bubbles.FakeBubbleFactory import com.android.wm.shell.common.TestShellExecutor import com.android.wm.shell.taskview.TaskView +import com.android.wm.shell.taskview.TaskViewController import com.android.wm.shell.taskview.TaskViewTaskController import com.google.common.truth.Truth.assertThat import java.util.concurrent.Semaphore @@ -58,6 +59,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.clearInvocations +import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @@ -165,7 +167,9 @@ class BubbleBarAnimationHelperTest { fun animateSwitch_bubbleToBubble_updateTaskBounds() { val fromBubble = createBubble("from").initialize(container) val toBubbleTaskController = mock<TaskViewTaskController>() - val toBubble = createBubble("to", toBubbleTaskController).initialize(container) + val taskController = mock<TaskViewController>() + val toBubble = createBubble("to", taskController, toBubbleTaskController).initialize( + container) activityScenario.onActivity { animationHelper.animateSwitch(fromBubble, toBubble) {} @@ -174,11 +178,11 @@ class BubbleBarAnimationHelperTest { } getInstrumentation().waitForIdleSync() // Clear invocations to ensure that bounds update happens after animation ends - clearInvocations(toBubbleTaskController) + clearInvocations(taskController) getInstrumentation().runOnMainSync { animatorTestRule.advanceTimeBy(900) } getInstrumentation().waitForIdleSync() - verify(toBubbleTaskController).setWindowBounds(any()) + verify(taskController).setTaskBounds(eq(toBubbleTaskController), any()) } @Test @@ -229,8 +233,9 @@ class BubbleBarAnimationHelperTest { @Test fun animateToRestPosition_updateTaskBounds() { - val taskController = mock<TaskViewTaskController>() - val bubble = createBubble("key", taskController).initialize(container) + val taskView = mock<TaskViewTaskController>() + val controller = mock<TaskViewController>() + val bubble = createBubble("key", controller, taskView).initialize(container) val semaphore = Semaphore(0) val after = Runnable { semaphore.release() } @@ -247,11 +252,11 @@ class BubbleBarAnimationHelperTest { animatorTestRule.advanceTimeBy(100) } // Clear invocations to ensure that bounds update happens after animation ends - clearInvocations(taskController) + clearInvocations(controller) getInstrumentation().runOnMainSync { animatorTestRule.advanceTimeBy(900) } getInstrumentation().waitForIdleSync() - verify(taskController).setWindowBounds(any()) + verify(controller).setTaskBounds(eq(taskView), any()) } @Test @@ -329,9 +334,10 @@ class BubbleBarAnimationHelperTest { private fun createBubble( key: String, + taskViewController: TaskViewController = mock<TaskViewController>(), taskViewTaskController: TaskViewTaskController = mock<TaskViewTaskController>(), ): Bubble { - val taskView = TaskView(context, taskViewTaskController) + val taskView = TaskView(context, taskViewController, taskViewTaskController) val taskInfo = mock<ActivityManager.RunningTaskInfo>() whenever(taskViewTaskController.taskInfo).thenReturn(taskInfo) val bubbleTaskView = BubbleTaskView(taskView, mainExecutor) diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt index fbbcff2dee92..7f65e22736b3 100644 --- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt @@ -46,6 +46,7 @@ import com.android.wm.shell.bubbles.UiEventSubject.Companion.assertThat import com.android.wm.shell.common.TestShellExecutor import com.android.wm.shell.shared.handles.RegionSamplingHelper import com.android.wm.shell.taskview.TaskView +import com.android.wm.shell.taskview.TaskViewController import com.android.wm.shell.taskview.TaskViewTaskController import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertWithMessage @@ -356,7 +357,7 @@ class BubbleBarExpandedViewTest { private inner class FakeBubbleTaskViewFactory : BubbleTaskViewFactory { override fun create(): BubbleTaskView { val taskViewTaskController = mock<TaskViewTaskController>() - val taskView = TaskView(context, taskViewTaskController) + val taskView = TaskView(context, mock<TaskViewController>(), taskViewTaskController) val taskInfo = mock<ActivityManager.RunningTaskInfo>() whenever(taskViewTaskController.taskInfo).thenReturn(taskInfo) return BubbleTaskView(taskView, mainExecutor) diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt index 5c5dde7da351..a6492476176b 100644 --- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt @@ -64,6 +64,7 @@ import com.android.wm.shell.shared.bubbles.BubbleBarLocation import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit +import com.android.wm.shell.taskview.TaskViewRepository import com.android.wm.shell.taskview.TaskViewTransitions import com.android.wm.shell.transition.Transitions import com.google.common.truth.Truth.assertThat @@ -194,6 +195,7 @@ class BubbleBarLayerViewTest { mainExecutor, mock<Handler>(), bgExecutor, + mock<TaskViewRepository>(), mock<TaskViewTransitions>(), mock<Transitions>(), SyncTransactionQueue(TransactionPool(), mainExecutor), diff --git a/libs/WindowManager/Shell/shared/Android.bp b/libs/WindowManager/Shell/shared/Android.bp index d7669ed5cf34..0974930adfa2 100644 --- a/libs/WindowManager/Shell/shared/Android.bp +++ b/libs/WindowManager/Shell/shared/Android.bp @@ -78,3 +78,17 @@ java_library { "com.android.window.flags.window-aconfig-java", ], } + +// Things that can be shared with launcher3 +java_library { + name: "WindowManager-Shell-shared-AOSP", + + sdk_version: "current", + + srcs: [ + "src/com/android/wm/shell/shared/bubbles/BubbleAnythingFlagHelper.java", + ], + static_libs: [ + "com_android_wm_shell_flags_lib", + ], +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index 08e36927d978..12dfbd9607e4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -117,6 +117,8 @@ import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.taskview.TaskView; +import com.android.wm.shell.taskview.TaskViewController; +import com.android.wm.shell.taskview.TaskViewRepository; import com.android.wm.shell.taskview.TaskViewTaskController; import com.android.wm.shell.taskview.TaskViewTransitions; import com.android.wm.shell.transition.Transitions; @@ -192,7 +194,7 @@ public class BubbleController implements ConfigurationChangeListener, private final TaskStackListenerImpl mTaskStackListener; private final ShellTaskOrganizer mTaskOrganizer; private final DisplayController mDisplayController; - private final TaskViewTransitions mTaskViewTransitions; + private final TaskViewController mTaskViewController; private final Transitions mTransitions; private final SyncTransactionQueue mSyncQueue; private final ShellController mShellController; @@ -309,6 +311,7 @@ public class BubbleController implements ConfigurationChangeListener, @ShellMainThread ShellExecutor mainExecutor, @ShellMainThread Handler mainHandler, @ShellBackgroundThread ShellExecutor bgExecutor, + TaskViewRepository taskViewRepository, TaskViewTransitions taskViewTransitions, Transitions transitions, SyncTransactionQueue syncQueue, @@ -347,7 +350,12 @@ public class BubbleController implements ConfigurationChangeListener, context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.importance_ring_stroke_width)); mDisplayController = displayController; - mTaskViewTransitions = taskViewTransitions; + if (TaskViewTransitions.useRepo()) { + mTaskViewController = new TaskViewTransitions(transitions, taskViewRepository, + organizer, syncQueue); + } else { + mTaskViewController = taskViewTransitions; + } mTransitions = transitions; mOneHandedOptional = oneHandedOptional; mDragAndDropController = dragAndDropController; @@ -359,8 +367,9 @@ public class BubbleController implements ConfigurationChangeListener, @Override public BubbleTaskView create() { TaskViewTaskController taskViewTaskController = new TaskViewTaskController( - context, organizer, taskViewTransitions, syncQueue); - TaskView taskView = new TaskView(context, taskViewTaskController); + context, organizer, mTaskViewController, syncQueue); + TaskView taskView = new TaskView(context, mTaskViewController, + taskViewTaskController); return new BubbleTaskView(taskView, mainExecutor); } }; @@ -843,14 +852,6 @@ public class BubbleController implements ConfigurationChangeListener, return mTaskOrganizer; } - SyncTransactionQueue getSyncTransactionQueue() { - return mSyncQueue; - } - - TaskViewTransitions getTaskViewTransitions() { - return mTaskViewTransitions; - } - /** Contains information to help position things on the screen. */ @VisibleForTesting public BubblePositioner getPositioner() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java index 72be066fc7a7..e69d60ddd6c6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java @@ -20,6 +20,7 @@ import android.annotation.Nullable; import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; +import android.graphics.RectF; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayTopology; import android.os.RemoteException; @@ -41,7 +42,9 @@ import com.android.wm.shell.shared.annotations.ShellMainThread; import com.android.wm.shell.sysui.ShellInit; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -62,6 +65,7 @@ public class DisplayController { private final SparseArray<DisplayRecord> mDisplays = new SparseArray<>(); private final ArrayList<OnDisplaysChangedListener> mDisplayChangedListeners = new ArrayList<>(); + private final Map<Integer, RectF> mUnpopulatedDisplayBounds = new HashMap<>(); public DisplayController(Context context, IWindowManager wmService, ShellInit shellInit, ShellExecutor mainExecutor, DisplayManager displayManager) { @@ -193,7 +197,12 @@ public class DisplayController { ? mContext : mContext.createDisplayContext(display); final DisplayRecord record = new DisplayRecord(displayId); - record.setDisplayLayout(context, new DisplayLayout(context, display)); + DisplayLayout displayLayout = new DisplayLayout(context, display); + if (Flags.enableConnectedDisplaysWindowDrag() + && mUnpopulatedDisplayBounds.containsKey(displayId)) { + displayLayout.setGlobalBoundsDp(mUnpopulatedDisplayBounds.get(displayId)); + } + record.setDisplayLayout(context, displayLayout); mDisplays.put(displayId, record); for (int i = 0; i < mDisplayChangedListeners.size(); ++i) { mDisplayChangedListeners.get(i).onDisplayAdded(displayId); @@ -231,10 +240,27 @@ public class DisplayController { } private void onDisplayTopologyChanged(DisplayTopology topology) { - // TODO(b/381472611): Call DisplayTopology#getCoordinates and update values in - // DisplayLayout when DM code is ready. + if (topology == null) { + return; + } + SparseArray<RectF> absoluteBounds = topology.getAbsoluteBounds(); + mUnpopulatedDisplayBounds.clear(); + for (int i = 0; i < absoluteBounds.size(); ++i) { + int displayId = absoluteBounds.keyAt(i); + DisplayLayout displayLayout = getDisplayLayout(displayId); + if (displayLayout == null) { + // onDisplayTopologyChanged can arrive before onDisplayAdded. + // Store the bounds to be applied later in onDisplayAdded. + Slog.d(TAG, "Storing bounds for onDisplayTopologyChanged on unknown" + + " display, displayId=" + displayId); + mUnpopulatedDisplayBounds.put(displayId, absoluteBounds.valueAt(i)); + } else { + displayLayout.setGlobalBoundsDp(absoluteBounds.valueAt(i)); + } + } + for (int i = 0; i < mDisplayChangedListeners.size(); ++i) { - mDisplayChangedListeners.get(i).onTopologyChanged(); + mDisplayChangedListeners.get(i).onTopologyChanged(topology); } } @@ -429,6 +455,6 @@ public class DisplayController { /** * Called when the display topology has changed. */ - default void onTopologyChanged() {} + default void onTopologyChanged(DisplayTopology topology) {} } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java index bcd40a9a9765..c4696d5f44f4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java @@ -192,15 +192,22 @@ public final class SyncTransactionQueue { throw new IllegalStateException("Sync Transactions must be serialized. In Flight: " + mInFlight.mId + " - " + mInFlight.mWCT); } - mInFlight = this; if (DEBUG) Slog.d(TAG, "Sending sync transaction: " + mWCT); - if (mLegacyTransition != null) { - mId = new WindowOrganizer().startLegacyTransition(mLegacyTransition.getType(), - mLegacyTransition.getAdapter(), this, mWCT); - } else { - mId = new WindowOrganizer().applySyncTransaction(mWCT, this); + try { + if (mLegacyTransition != null) { + mId = new WindowOrganizer().startLegacyTransition(mLegacyTransition.getType(), + mLegacyTransition.getAdapter(), this, mWCT); + } else { + mId = new WindowOrganizer().applySyncTransaction(mWCT, this); + } + } catch (RuntimeException e) { + Slog.e(TAG, "Send failed", e); + // Finish current sync callback immediately. + onTransactionReady(mId, new SurfaceControl.Transaction()); + return; } if (DEBUG) Slog.d(TAG, " Sent sync transaction. Got id=" + mId); + mInFlight = this; mMainExecutor.executeDelayed(mOnReplyTimeout, REPLY_TIMEOUT); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/IPip.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/IPip.aidl index e77987963b48..37779077f9b6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/IPip.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/IPip.aidl @@ -16,6 +16,7 @@ package com.android.wm.shell.common.pip; +import android.app.ActivityManager; import android.app.PictureInPictureParams; import android.view.SurfaceControl; import android.content.ComponentName; @@ -41,9 +42,8 @@ interface IPip { bounds * @return destination bounds the PiP window should land into */ - Rect startSwipePipToHome(in ComponentName componentName, in ActivityInfo activityInfo, - in PictureInPictureParams pictureInPictureParams, - int launcherRotation, in Rect hotseatKeepClearArea) = 1; + Rect startSwipePipToHome(in ActivityManager.RunningTaskInfo taskInfo, int launcherRotation, + in Rect hotseatKeepClearArea) = 1; /** * Notifies the swiping Activity to PiP onto home transition is finished diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index cbbe8a2b5613..84042591ad1b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -771,8 +771,9 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static TaskViewTransitions provideTaskViewTransitions(Transitions transitions, - TaskViewRepository repository) { - return new TaskViewTransitions(transitions, repository); + TaskViewRepository repository, ShellTaskOrganizer organizer, + SyncTransactionQueue syncQueue) { + return new TaskViewTransitions(transitions, repository, organizer, syncQueue); } @WMSingleton diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index 408160d30467..67e345365d26 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -133,6 +133,7 @@ import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; +import com.android.wm.shell.taskview.TaskViewRepository; import com.android.wm.shell.taskview.TaskViewTransitions; import com.android.wm.shell.transition.DefaultMixedHandler; import com.android.wm.shell.transition.FocusTransitionObserver; @@ -247,6 +248,7 @@ public abstract class WMShellModule { @ShellMainThread ShellExecutor mainExecutor, @ShellMainThread Handler mainHandler, @ShellBackgroundThread ShellExecutor bgExecutor, + TaskViewRepository taskViewRepository, TaskViewTransitions taskViewTransitions, Transitions transitions, SyncTransactionQueue syncQueue, @@ -280,6 +282,7 @@ public abstract class WMShellModule { mainExecutor, mainHandler, bgExecutor, + taskViewRepository, taskViewTransitions, transitions, syncQueue, @@ -1028,8 +1031,9 @@ public abstract class WMShellModule { static CloseDesktopTaskTransitionHandler provideCloseDesktopTaskTransitionHandler( Context context, @ShellMainThread ShellExecutor mainExecutor, - @ShellAnimationThread ShellExecutor animExecutor) { - return new CloseDesktopTaskTransitionHandler(context, mainExecutor, animExecutor); + @ShellAnimationThread ShellExecutor animExecutor, + @ShellMainThread Handler handler) { + return new CloseDesktopTaskTransitionHandler(context, mainExecutor, animExecutor, handler); } @WMSingleton diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java index c8d0dab39837..793bdf0b5614 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java @@ -83,13 +83,14 @@ public abstract class Pip2Module { @NonNull PipTransitionState pipStackListenerController, @NonNull PipDisplayLayoutState pipDisplayLayoutState, @NonNull PipUiStateChangeController pipUiStateChangeController, + DisplayController displayController, Optional<DesktopUserRepositories> desktopUserRepositoriesOptional, Optional<DesktopWallpaperActivityTokenProvider> desktopWallpaperActivityTokenProviderOptional) { return new PipTransition(context, shellInit, shellTaskOrganizer, transitions, pipBoundsState, null, pipBoundsAlgorithm, pipTaskListener, pipScheduler, pipStackListenerController, pipDisplayLayoutState, - pipUiStateChangeController, desktopUserRepositoriesOptional, + pipUiStateChangeController, displayController, desktopUserRepositoriesOptional, desktopWallpaperActivityTokenProviderOptional); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/CloseDesktopTaskTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/CloseDesktopTaskTransitionHandler.kt index 9b5a28916148..1ce093e02a4a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/CloseDesktopTaskTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/CloseDesktopTaskTransitionHandler.kt @@ -23,8 +23,10 @@ import android.animation.ValueAnimator import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.content.Context import android.graphics.Rect +import android.os.Handler import android.os.IBinder import android.util.TypedValue +import android.view.Choreographer import android.view.SurfaceControl.Transaction import android.view.WindowManager import android.window.TransitionInfo @@ -32,7 +34,10 @@ import android.window.TransitionRequestInfo import android.window.WindowContainerTransaction import androidx.core.animation.addListener import com.android.app.animation.Interpolators +import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_CLOSE_TASK +import com.android.internal.jank.InteractionJankMonitor import com.android.wm.shell.common.ShellExecutor +import com.android.wm.shell.shared.annotations.ShellMainThread import com.android.wm.shell.transition.Transitions import java.util.function.Supplier @@ -44,9 +49,11 @@ constructor( private val mainExecutor: ShellExecutor, private val animExecutor: ShellExecutor, private val transactionSupplier: Supplier<Transaction> = Supplier { Transaction() }, + @ShellMainThread private val handler: Handler, ) : Transitions.TransitionHandler { private val runningAnimations = mutableMapOf<IBinder, List<Animator>>() + private val interactionJankMonitor = InteractionJankMonitor.getInstance() /** Returns null, as it only handles transitions started from Shell. */ override fun handleRequest( @@ -71,18 +78,27 @@ constructor( // All animations completed, finish the transition runningAnimations.remove(transition) finishCallback.onTransitionFinished(/* wct= */ null) + interactionJankMonitor.end(CUJ_DESKTOP_MODE_CLOSE_TASK) } } } + val closingChanges = + info.changes.filter { + it.mode == WindowManager.TRANSIT_CLOSE && + it.taskInfo?.windowingMode == WINDOWING_MODE_FREEFORM + } animations += - info.changes - .filter { - it.mode == WindowManager.TRANSIT_CLOSE && - it.taskInfo?.windowingMode == WINDOWING_MODE_FREEFORM - } - .map { createCloseAnimation(it, finishTransaction, onAnimFinish) } + closingChanges.map { createCloseAnimation(it, finishTransaction, onAnimFinish) } if (animations.isEmpty()) return false runningAnimations[transition] = animations + closingChanges.lastOrNull()?.leash?.let { lastChangeLeash -> + interactionJankMonitor.begin( + lastChangeLeash, + context, + handler, + CUJ_DESKTOP_MODE_CLOSE_TASK, + ) + } animExecutor.execute { animations.forEach(Animator::start) } return true } @@ -127,6 +143,7 @@ constructor( .get() .setPosition(change.leash, animBounds.left.toFloat(), animBounds.top.toFloat()) .setScale(change.leash, animScale, animScale) + .setFrameTimeline(Choreographer.getInstance().vsyncId) .apply() } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 9c3e815b389d..912d3839fae7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -1317,14 +1317,14 @@ public class PipController implements PipTransitionController.PipTransitionCallb } @Override - public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo, - PictureInPictureParams pictureInPictureParams, int launcherRotation, - Rect keepClearArea) { + public Rect startSwipePipToHome(ActivityManager.RunningTaskInfo taskInfo, + int launcherRotation, Rect keepClearArea) { Rect[] result = new Rect[1]; executeRemoteCallWithTaskPermission(mController, "startSwipePipToHome", (controller) -> { - result[0] = controller.startSwipePipToHome(componentName, activityInfo, - pictureInPictureParams, launcherRotation, keepClearArea); + result[0] = controller.startSwipePipToHome(taskInfo.topActivity, + taskInfo.topActivityInfo, taskInfo.pictureInPictureParams, + launcherRotation, keepClearArea); }, true /* blocking */); return result[0]; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipAlphaAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipAlphaAnimator.java index 63c151268bdb..a033b824aa28 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipAlphaAnimator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipAlphaAnimator.java @@ -50,6 +50,11 @@ public class PipAlphaAnimator extends ValueAnimator { private final SurfaceControl mLeash; private final SurfaceControl.Transaction mStartTransaction; + private final SurfaceControl.Transaction mFinishTransaction; + + private final int mDirection; + private final int mCornerRadius; + private final int mShadowRadius; private final Animator.AnimatorListener mAnimatorListener = new AnimatorListenerAdapter() { @Override @@ -59,6 +64,7 @@ public class PipAlphaAnimator extends ValueAnimator { mAnimationStartCallback.run(); } if (mStartTransaction != null) { + onAlphaAnimationUpdate(getStartAlphaValue(), mStartTransaction); mStartTransaction.apply(); } } @@ -66,6 +72,10 @@ public class PipAlphaAnimator extends ValueAnimator { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); + if (mFinishTransaction != null) { + onAlphaAnimationUpdate(getEndAlphaValue(), mFinishTransaction); + mFinishTransaction.apply(); + } if (mAnimationEndCallback != null) { mAnimationEndCallback.run(); } @@ -77,8 +87,9 @@ public class PipAlphaAnimator extends ValueAnimator { @Override public void onAnimationUpdate(@NonNull ValueAnimator animation) { final float alpha = (Float) animation.getAnimatedValue(); - mSurfaceControlTransactionFactory.getTransaction() - .setAlpha(mLeash, alpha).apply(); + final SurfaceControl.Transaction tx = + mSurfaceControlTransactionFactory.getTransaction(); + onAlphaAnimationUpdate(alpha, tx); } }; @@ -91,19 +102,21 @@ public class PipAlphaAnimator extends ValueAnimator { public PipAlphaAnimator(Context context, SurfaceControl leash, - SurfaceControl.Transaction tx, + SurfaceControl.Transaction startTransaction, + SurfaceControl.Transaction finishTransaction, @Fade int direction) { mLeash = leash; - mStartTransaction = tx; - if (direction == FADE_IN) { - setFloatValues(0f, 1f); - } else { // direction == FADE_OUT - setFloatValues(1f, 0f); - } + mStartTransaction = startTransaction; + mFinishTransaction = finishTransaction; + + mDirection = direction; + setFloatValues(getStartAlphaValue(), getEndAlphaValue()); mSurfaceControlTransactionFactory = new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory(); final int enterAnimationDuration = context.getResources() .getInteger(R.integer.config_pipEnterAnimationDuration); + mCornerRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius); + mShadowRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius); setDuration(enterAnimationDuration); addListener(mAnimatorListener); addUpdateListener(mAnimatorUpdateListener); @@ -117,6 +130,21 @@ public class PipAlphaAnimator extends ValueAnimator { mAnimationEndCallback = runnable; } + private void onAlphaAnimationUpdate(float alpha, SurfaceControl.Transaction tx) { + tx.setAlpha(mLeash, alpha) + .setCornerRadius(mLeash, mCornerRadius) + .setShadowRadius(mLeash, mShadowRadius); + tx.apply(); + } + + private float getStartAlphaValue() { + return mDirection == FADE_IN ? 0f : 1f; + } + + private float getEndAlphaValue() { + return mDirection == FADE_IN ? 1f : 0f; + } + @VisibleForTesting void setSurfaceControlTransactionFactory( @NonNull PipSurfaceTransactionHelper.SurfaceControlTransactionFactory factory) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java index 562b26014bf3..b1984ccef4cb 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java @@ -40,6 +40,7 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.ProtoLog; import com.android.internal.util.Preconditions; +import com.android.window.flags.Flags; import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayChangeController; @@ -358,10 +359,21 @@ public class PipController implements ConfigurationChangeListener, // private Rect getSwipePipToHomeBounds(ComponentName componentName, ActivityInfo activityInfo, - PictureInPictureParams pictureInPictureParams, + int displayId, PictureInPictureParams pictureInPictureParams, int launcherRotation, Rect hotseatKeepClearArea) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "getSwipePipToHomeBounds: %s", componentName); + + // If PiP is enabled on Connected Displays, update PipDisplayLayoutState to have the correct + // display info that PiP is entering in. + if (Flags.enableConnectedDisplaysPip()) { + final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(displayId); + if (displayLayout != null) { + mPipDisplayLayoutState.setDisplayId(displayId); + mPipDisplayLayoutState.setDisplayLayout(displayLayout); + } + } + // Preemptively add the keep clear area for Hotseat, so that it is taken into account // when calculating the entry destination bounds of PiP window. mPipBoundsState.setNamedUnrestrictedKeepClearArea( @@ -592,14 +604,14 @@ public class PipController implements ConfigurationChangeListener, } @Override - public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo, - PictureInPictureParams pictureInPictureParams, int launcherRotation, - Rect keepClearArea) { + public Rect startSwipePipToHome(ActivityManager.RunningTaskInfo taskInfo, + int launcherRotation, Rect keepClearArea) { Rect[] result = new Rect[1]; executeRemoteCallWithTaskPermission(mController, "startSwipePipToHome", (controller) -> { - result[0] = controller.getSwipePipToHomeBounds(componentName, activityInfo, - pictureInPictureParams, launcherRotation, keepClearArea); + result[0] = controller.getSwipePipToHomeBounds(taskInfo.topActivity, + taskInfo.topActivityInfo, taskInfo.displayId, + taskInfo.pictureInPictureParams, launcherRotation, keepClearArea); }, true /* blocking */); return result[0]; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java index ed532cad0523..21b0820f523a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java @@ -294,7 +294,8 @@ public class PipScheduler { interface PipAlphaAnimatorSupplier { PipAlphaAnimator get(@NonNull Context context, SurfaceControl leash, - SurfaceControl.Transaction tx, + SurfaceControl.Transaction startTransaction, + SurfaceControl.Transaction finishTransaction, @PipAlphaAnimator.Fade int direction); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java index 4902455cae16..8cba076d28f2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java @@ -59,6 +59,8 @@ import com.android.internal.util.Preconditions; import com.android.window.flags.Flags; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.ComponentUtils; +import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.pip.PipBoundsAlgorithm; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.common.pip.PipDisplayLayoutState; @@ -112,6 +114,7 @@ public class PipTransition extends PipTransitionController implements private final PipScheduler mPipScheduler; private final PipTransitionState mPipTransitionState; private final PipDisplayLayoutState mPipDisplayLayoutState; + private final DisplayController mDisplayController; private final Optional<DesktopUserRepositories> mDesktopUserRepositoriesOptional; private final Optional<DesktopWallpaperActivityTokenProvider> mDesktopWallpaperActivityTokenProviderOptional; @@ -151,6 +154,7 @@ public class PipTransition extends PipTransitionController implements PipTransitionState pipTransitionState, PipDisplayLayoutState pipDisplayLayoutState, PipUiStateChangeController pipUiStateChangeController, + DisplayController displayController, Optional<DesktopUserRepositories> desktopUserRepositoriesOptional, Optional<DesktopWallpaperActivityTokenProvider> desktopWallpaperActivityTokenProviderOptional) { @@ -164,6 +168,7 @@ public class PipTransition extends PipTransitionController implements mPipTransitionState = pipTransitionState; mPipTransitionState.addPipTransitionStateChangedListener(this); mPipDisplayLayoutState = pipDisplayLayoutState; + mDisplayController = displayController; mDesktopUserRepositoriesOptional = desktopUserRepositoriesOptional; mDesktopWallpaperActivityTokenProviderOptional = desktopWallpaperActivityTokenProviderOptional; @@ -513,7 +518,7 @@ public class PipTransition extends PipTransitionController implements private void startOverlayFadeoutAnimation(@NonNull SurfaceControl overlayLeash, @NonNull Runnable onAnimationEnd) { PipAlphaAnimator animator = new PipAlphaAnimator(mContext, overlayLeash, - null /* startTx */, PipAlphaAnimator.FADE_OUT); + null /* startTx */, null /* finishTx */, PipAlphaAnimator.FADE_OUT); animator.setDuration(CONTENT_OVERLAY_FADE_OUT_DELAY_MS); animator.setAnimationEndCallback(onAnimationEnd); animator.start(); @@ -604,7 +609,7 @@ public class PipTransition extends PipTransitionController implements .setAlpha(pipLeash, 0f); PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipLeash, startTransaction, - PipAlphaAnimator.FADE_IN); + finishTransaction, PipAlphaAnimator.FADE_IN); // This should update the pip transition state accordingly after we stop playing. animator.setAnimationEndCallback(this::finishTransition); cacheAndStartTransitionAnimator(animator); @@ -699,7 +704,7 @@ public class PipTransition extends PipTransitionController implements finishTransaction.setAlpha(pipChange.getLeash(), 0f); if (mPendingRemoveWithFadeout) { PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipChange.getLeash(), - startTransaction, PipAlphaAnimator.FADE_OUT); + startTransaction, finishTransaction, PipAlphaAnimator.FADE_OUT); animator.setAnimationEndCallback(this::finishTransition); animator.start(); } else { @@ -824,6 +829,17 @@ public class PipTransition extends PipTransitionController implements mPipBoundsState.setBoundsStateForEntry(pipTask.topActivity, pipTask.topActivityInfo, pipParams, mPipBoundsAlgorithm); + // If PiP is enabled on Connected Displays, update PipDisplayLayoutState to have the correct + // display info that PiP is entering in. + if (Flags.enableConnectedDisplaysPip()) { + final DisplayLayout displayLayout = mDisplayController.getDisplayLayout( + pipTask.displayId); + if (displayLayout != null) { + mPipDisplayLayoutState.setDisplayId(pipTask.displayId); + mPipDisplayLayoutState.setDisplayLayout(displayLayout); + } + } + // calculate the entry bounds and notify core to move task to pinned with final bounds final Rect entryBounds = mPipBoundsAlgorithm.getEntryDestinationBounds(); mPipBoundsState.setBounds(entryBounds); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java index 36eaebdf4fff..afc6fee2eca3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java @@ -228,7 +228,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, break; } } - final int transitionType = Flags.enableShellTopTaskTracking() + final int transitionType = Flags.enableRecentsBookendTransition() ? TRANSIT_START_RECENTS_TRANSITION : TRANSIT_TO_FRONT; final IBinder transition = mTransitions.startTransition(transitionType, @@ -920,7 +920,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, return; } - if (Flags.enableShellTopTaskTracking() + if (Flags.enableRecentsBookendTransition() && info.getType() == TRANSIT_END_RECENTS_TRANSITION && mergeTarget == mTransition) { // This is a pending finish, so merge the end transition to trigger completing the @@ -1290,8 +1290,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, return; } - if (mFinishCB == null - || (Flags.enableShellTopTaskTracking() && mPendingFinishTransition != null)) { + if (mFinishCB == null || (Flags.enableRecentsBookendTransition() + && mPendingFinishTransition != null)) { Slog.e(TAG, "Duplicate call to finish"); if (runnerFinishCb != null) { try { @@ -1310,7 +1310,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, && !mWillFinishToHome && mPausingTasks != null && mState == STATE_NORMAL; - if (!Flags.enableShellTopTaskTracking()) { + if (!Flags.enableRecentsBookendTransition()) { // This is only necessary when the recents transition is finished using a finishWCT, // otherwise a new transition will notify the relevant observers if (returningToApp && allAppsAreTranslucent(mPausingTasks)) { @@ -1443,7 +1443,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, // We need to clear the WCT to send finishWCT=null for Recents. wct.clear(); - if (Flags.enableShellTopTaskTracking()) { + if (Flags.enableRecentsBookendTransition()) { // In this case, we've already started the PIP transition, so we can // clean up immediately mPendingRunnerFinishCb = runnerFinishCb; @@ -1455,7 +1455,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, } } - if (Flags.enableShellTopTaskTracking()) { + if (Flags.enableRecentsBookendTransition()) { if (!wct.isEmpty()) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.finishInner: " @@ -1574,7 +1574,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, /** * A temporary transition handler used with the pending finish transition, which runs the * cleanup/finish logic once the pending transition is merged/handled. - * This is only initialized if Flags.enableShellTopTaskTracking() is enabled. + * This is only initialized if Flags.enableRecentsBookendTransition() is enabled. */ private class PendingFinishTransitionHandler implements Transitions.TransitionHandler { @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index c9136b4ad18d..37c93518998a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -138,6 +138,7 @@ import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.LaunchAdjacentController; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; +import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.common.split.OffscreenTouchZone; import com.android.wm.shell.common.split.SplitDecorManager; import com.android.wm.shell.common.split.SplitLayout; @@ -556,6 +557,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, return true; } + if (PipUtils.isPip2ExperimentEnabled() + && request.getPipChange() != null && getSplitPosition( + request.getPipChange().getTaskInfo().taskId) != SPLIT_POSITION_UNDEFINED) { + // In PiP2, PiP-able task can also come in through the pip change request field. + return true; + } + // If one of the splitting tasks support auto-pip, wm-core might reparent the task to TDA // and file a TRANSIT_PIP transition when finishing transitions. // @see com.android.server.wm.RootWindowContainer#moveActivityToPinnedRootTask diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java index 361d766370e5..0445add9cba9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java @@ -74,13 +74,16 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, private final Rect mTmpRootRect = new Rect(); private final int[] mTmpLocation = new int[2]; private final Rect mBoundsOnScreen = new Rect(); + private final TaskViewController mTaskViewController; private final TaskViewTaskController mTaskViewTaskController; private Region mObscuredTouchRegion; private Insets mCaptionInsets; private Handler mHandler; - public TaskView(Context context, TaskViewTaskController taskViewTaskController) { + public TaskView(Context context, TaskViewController taskViewController, + TaskViewTaskController taskViewTaskController) { super(context, null, 0, 0, true /* disableBackgroundLayer */); + mTaskViewController = taskViewController; mTaskViewTaskController = taskViewTaskController; // TODO(b/266736992): Think about a better way to set the TaskViewBase on the // TaskViewTaskController and vice-versa @@ -100,7 +103,8 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, */ public void startActivity(@NonNull PendingIntent pendingIntent, @Nullable Intent fillInIntent, @NonNull ActivityOptions options, @Nullable Rect launchBounds) { - mTaskViewTaskController.startActivity(pendingIntent, fillInIntent, options, launchBounds); + mTaskViewController.startActivity(mTaskViewTaskController, pendingIntent, fillInIntent, + options, launchBounds); } /** @@ -115,19 +119,20 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, */ public void startShortcutActivity(@NonNull ShortcutInfo shortcut, @NonNull ActivityOptions options, @Nullable Rect launchBounds) { - mTaskViewTaskController.startShortcutActivity(shortcut, options, launchBounds); + mTaskViewController.startShortcutActivity(mTaskViewTaskController, shortcut, options, + launchBounds); } /** * Moves the current task in taskview out of the view and back to fullscreen. */ public void moveToFullscreen() { - mTaskViewTaskController.moveToFullscreen(); + mTaskViewController.moveTaskViewToFullscreen(mTaskViewTaskController); } @Override public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { - if (mTaskViewTaskController.isUsingShellTransitions()) { + if (mTaskViewController.isUsingShellTransitions()) { // No need for additional work as it is already taken care of during // prepareOpenAnimation(). return; @@ -222,14 +227,14 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, */ public void onLocationChanged() { getBoundsOnScreen(mTmpRect); - mTaskViewTaskController.setWindowBounds(mTmpRect); + mTaskViewController.setTaskBounds(mTaskViewTaskController, mTmpRect); } /** * Call to remove the task from window manager. This task will not appear in recents. */ public void removeTask() { - mTaskViewTaskController.removeTask(); + mTaskViewController.removeTaskView(mTaskViewTaskController, null /* token */); } /** @@ -254,7 +259,7 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, public void surfaceChanged(@androidx.annotation.NonNull SurfaceHolder holder, int format, int width, int height) { getBoundsOnScreen(mTmpRect); - mTaskViewTaskController.setWindowBounds(mTmpRect); + mTaskViewController.setTaskBounds(mTaskViewTaskController, mTmpRect); } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewController.java new file mode 100644 index 000000000000..59becf73e90b --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewController.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2025 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.wm.shell.taskview; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.ActivityOptions; +import android.app.PendingIntent; +import android.content.Intent; +import android.content.pm.LauncherApps; +import android.content.pm.ShortcutInfo; +import android.graphics.Rect; +import android.view.SurfaceControl; +import android.window.WindowContainerToken; +import android.window.WindowContainerTransaction; + +import com.android.wm.shell.ShellTaskOrganizer; + +/** + * Interface which provides methods to control TaskView properties and state. + * + * <ul> + * <li>To start an activity based task view, use {@link #startActivity}</li> + * + * <li>To start an activity (represented by {@link ShortcutInfo}) based task view, use + * {@link #startShortcutActivity} + * </li> + * + * <li>To start a root-task based task view, use {@link #startRootTask}. + * This method is special as it doesn't create a root task and instead expects that the + * launch root task is already created and started. This method just attaches the taskInfo to + * the TaskView. + * </li> + * </ul> + */ +public interface TaskViewController { + /** Registers a TaskView with this controller. */ + void registerTaskView(@NonNull TaskViewTaskController tv); + + /** Un-registers a TaskView from this controller. */ + void unregisterTaskView(@NonNull TaskViewTaskController tv); + + /** + * Launch an activity represented by {@link ShortcutInfo}. + * <p>The owner of this container must be allowed to access the shortcut information, + * as defined in {@link LauncherApps#hasShortcutHostPermission()} to use this method. + * + * @param destination the TaskView to start the shortcut into. + * @param shortcut the shortcut used to launch the activity. + * @param options options for the activity. + * @param launchBounds the bounds (window size and position) that the activity should be + * launched in, in pixels and in screen coordinates. + */ + void startShortcutActivity(@NonNull TaskViewTaskController destination, + @NonNull ShortcutInfo shortcut, + @NonNull ActivityOptions options, @Nullable Rect launchBounds); + + /** + * Launch a new activity into a TaskView + * + * @param destination The TaskView to start the activity into. + * @param pendingIntent Intent used to launch an activity. + * @param fillInIntent Additional Intent data, see {@link Intent#fillIn Intent.fillIn()} + * @param options options for the activity. + * @param launchBounds the bounds (window size and position) that the activity should be + * launched in, in pixels and in screen coordinates. + */ + void startActivity(@NonNull TaskViewTaskController destination, + @NonNull PendingIntent pendingIntent, @Nullable Intent fillInIntent, + @NonNull ActivityOptions options, @Nullable Rect launchBounds); + + /** + * Attaches the given root task {@code taskInfo} in the task view. + * + * <p> Since {@link ShellTaskOrganizer#createRootTask(int, int, + * ShellTaskOrganizer.TaskListener)} does not use the shell transitions flow, this method is + * used as an entry point for an already-created root-task in the task view. + * + * @param destination The TaskView to put the root-task into. + * @param taskInfo the task info of the root task. + * @param leash the {@link android.content.pm.ShortcutInfo.Surface} of the root task + * @param wct The Window container work that should happen as part of this set up. + */ + void startRootTask(@NonNull TaskViewTaskController destination, + ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash, + @Nullable WindowContainerTransaction wct); + + /** + * Closes a taskview and removes the task from window manager. This task will not appear in + * recents. + */ + void removeTaskView(@NonNull TaskViewTaskController taskView, + @Nullable WindowContainerToken taskToken); + + /** + * Moves the current task in TaskView out of the view and back to fullscreen. + */ + void moveTaskViewToFullscreen(@NonNull TaskViewTaskController taskView); + + /** + * Starts a new transition to make the given {@code taskView} visible and optionally change + * the task order. + * + * @param taskView the task view which the visibility is being changed for + * @param visible the new visibility of the task view + */ + void setTaskViewVisible(TaskViewTaskController taskView, boolean visible); + + /** + * Sets the task bounds to {@code boundsOnScreen}. + * Usually called when the taskview's position or size has changed. + * + * @param boundsOnScreen the on screen bounds of the surface view. + */ + void setTaskBounds(TaskViewTaskController taskView, Rect boundsOnScreen); + + /** Whether shell-transitions are currently enabled. */ + boolean isUsingShellTransitions(); +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewFactoryController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewFactoryController.java index e4fcff0c372a..b2813bb382ea 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewFactoryController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewFactoryController.java @@ -32,16 +32,16 @@ public class TaskViewFactoryController { private final ShellTaskOrganizer mTaskOrganizer; private final ShellExecutor mShellExecutor; private final SyncTransactionQueue mSyncQueue; - private final TaskViewTransitions mTaskViewTransitions; + private final TaskViewController mTaskViewController; private final TaskViewFactory mImpl = new TaskViewFactoryImpl(); public TaskViewFactoryController(ShellTaskOrganizer taskOrganizer, ShellExecutor shellExecutor, SyncTransactionQueue syncQueue, - TaskViewTransitions taskViewTransitions) { + TaskViewController taskViewController) { mTaskOrganizer = taskOrganizer; mShellExecutor = shellExecutor; mSyncQueue = syncQueue; - mTaskViewTransitions = taskViewTransitions; + mTaskViewController = taskViewController; } public TaskViewFactoryController(ShellTaskOrganizer taskOrganizer, @@ -49,7 +49,7 @@ public class TaskViewFactoryController { mTaskOrganizer = taskOrganizer; mShellExecutor = shellExecutor; mSyncQueue = syncQueue; - mTaskViewTransitions = null; + mTaskViewController = null; } /** @@ -61,8 +61,8 @@ public class TaskViewFactoryController { /** Creates an {@link TaskView} */ public void create(@UiContext Context context, Executor executor, Consumer<TaskView> onCreate) { - TaskView taskView = new TaskView(context, new TaskViewTaskController(context, - mTaskOrganizer, mTaskViewTransitions, mSyncQueue)); + TaskView taskView = new TaskView(context, mTaskViewController, new TaskViewTaskController( + context, mTaskOrganizer, mTaskViewController, mSyncQueue)); executor.execute(() -> { onCreate.accept(taskView); }); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java index 5c7dd078ee45..d19a7eac6ad2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java @@ -16,32 +16,21 @@ package com.android.wm.shell.taskview; -import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; -import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; -import static android.view.WindowManager.TRANSIT_CHANGE; - import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; -import android.app.ActivityOptions; -import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; -import android.content.Intent; -import android.content.pm.LauncherApps; -import android.content.pm.ShortcutInfo; import android.graphics.Rect; import android.gui.TrustedOverlay; import android.os.Binder; import android.util.CloseGuard; -import android.util.Slog; import android.view.SurfaceControl; import android.view.WindowInsets; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import com.android.internal.annotations.VisibleForTesting; -import com.android.wm.shell.Flags; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.SyncTransactionQueue; @@ -49,27 +38,10 @@ import java.io.PrintWriter; import java.util.concurrent.Executor; /** - * This class implements the core logic to show a task on the {@link TaskView}. All the {@link + * This class represents the visible aspect of a task in a {@link TaskView}. All the {@link * TaskView} to {@link TaskViewTaskController} interactions are done via direct method calls. * * The reverse communication is done via the {@link TaskViewBase} interface. - * - * <ul> - * <li>The entry point for an activity based task view is {@link - * TaskViewTaskController#startActivity(PendingIntent, Intent, ActivityOptions, Rect)}</li> - * - * <li>The entry point for an activity (represented by {@link ShortcutInfo}) based task view - * is {@link TaskViewTaskController#startShortcutActivity(ShortcutInfo, ActivityOptions, Rect)} - * </li> - * - * <li>The entry point for a root-task based task view is {@link - * TaskViewTaskController#startRootTask(ActivityManager.RunningTaskInfo, SurfaceControl, - * WindowContainerTransaction)}. - * This method is special as it doesn't create a root task and instead expects that the - * launch root task is already created and started. This method just attaches the taskInfo to - * the TaskView. - * </li> - * </ul> */ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { @@ -82,7 +54,7 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { private final ShellTaskOrganizer mTaskOrganizer; private final Executor mShellExecutor; private final SyncTransactionQueue mSyncQueue; - private final TaskViewTransitions mTaskViewTransitions; + private final TaskViewController mTaskViewController; private final Context mContext; /** @@ -109,15 +81,15 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { private Rect mCaptionInsets; public TaskViewTaskController(Context context, ShellTaskOrganizer organizer, - TaskViewTransitions taskViewTransitions, SyncTransactionQueue syncQueue) { + TaskViewController taskViewController, SyncTransactionQueue syncQueue) { mContext = context; mTaskOrganizer = organizer; mShellExecutor = organizer.getExecutor(); mSyncQueue = syncQueue; - mTaskViewTransitions = taskViewTransitions; + mTaskViewController = taskViewController; mShellExecutor.execute(() -> { - if (mTaskViewTransitions != null) { - mTaskViewTransitions.addTaskView(this); + if (mTaskViewController != null) { + mTaskViewController.registerTaskView(this); } }); mGuard.open("release"); @@ -140,6 +112,10 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { return mSurfaceControl; } + Context getContext() { + return mContext; + } + /** * Sets the provided {@link TaskViewBase}, which is used to notify the client part about the * task related changes and getting the current bounds. @@ -155,9 +131,12 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { return mIsInitialized; } - /** Until all users are converted, we may have mixed-use (eg. Car). */ - public boolean isUsingShellTransitions() { - return mTaskViewTransitions != null && mTaskViewTransitions.isEnabled(); + WindowContainerToken getTaskToken() { + return mTaskToken; + } + + void setResizeBgColor(SurfaceControl.Transaction t, int bgColor) { + mTaskViewBase.setResizeBgColor(t, bgColor); } /** @@ -173,122 +152,6 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { } /** - * Launch an activity represented by {@link ShortcutInfo}. - * <p>The owner of this container must be allowed to access the shortcut information, - * as defined in {@link LauncherApps#hasShortcutHostPermission()} to use this method. - * - * @param shortcut the shortcut used to launch the activity. - * @param options options for the activity. - * @param launchBounds the bounds (window size and position) that the activity should be - * launched in, in pixels and in screen coordinates. - */ - public void startShortcutActivity(@NonNull ShortcutInfo shortcut, - @NonNull ActivityOptions options, @Nullable Rect launchBounds) { - prepareActivityOptions(options, launchBounds); - LauncherApps service = mContext.getSystemService(LauncherApps.class); - if (isUsingShellTransitions()) { - mShellExecutor.execute(() -> { - final WindowContainerTransaction wct = new WindowContainerTransaction(); - wct.startShortcut(mContext.getPackageName(), shortcut, options.toBundle()); - mTaskViewTransitions.startTaskView(wct, this, options.getLaunchCookie()); - }); - return; - } - try { - service.startShortcut(shortcut, null /* sourceBounds */, options.toBundle()); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /** - * Launch a new activity. - * - * @param pendingIntent Intent used to launch an activity. - * @param fillInIntent Additional Intent data, see {@link Intent#fillIn Intent.fillIn()} - * @param options options for the activity. - * @param launchBounds the bounds (window size and position) that the activity should be - * launched in, in pixels and in screen coordinates. - */ - public void startActivity(@NonNull PendingIntent pendingIntent, @Nullable Intent fillInIntent, - @NonNull ActivityOptions options, @Nullable Rect launchBounds) { - prepareActivityOptions(options, launchBounds); - if (isUsingShellTransitions()) { - mShellExecutor.execute(() -> { - WindowContainerTransaction wct = new WindowContainerTransaction(); - wct.sendPendingIntent(pendingIntent, fillInIntent, options.toBundle()); - mTaskViewTransitions.startTaskView(wct, this, options.getLaunchCookie()); - }); - return; - } - try { - pendingIntent.send(mContext, 0 /* code */, fillInIntent, - null /* onFinished */, null /* handler */, null /* requiredPermission */, - options.toBundle()); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - - /** - * Attaches the given root task {@code taskInfo} in the task view. - * - * <p> Since {@link ShellTaskOrganizer#createRootTask(int, int, - * ShellTaskOrganizer.TaskListener)} does not use the shell transitions flow, this method is - * used as an entry point for an already-created root-task in the task view. - * - * @param taskInfo the task info of the root task. - * @param leash the {@link android.content.pm.ShortcutInfo.Surface} of the root task - * @param wct The Window container work that should happen as part of this set up. - */ - public void startRootTask(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash, - @Nullable WindowContainerTransaction wct) { - if (wct == null) { - wct = new WindowContainerTransaction(); - } - // This method skips the regular flow where an activity task is launched as part of a new - // transition in taskview and then transition is intercepted using the launchcookie. - // The task here is already created and running, it just needs to be reparented, resized - // and tracked correctly inside taskview. Which is done by calling - // prepareOpenAnimationInternal() and then manually enqueuing the resulting window container - // transaction. - prepareOpenAnimationInternal(true /* newTask */, mTransaction /* startTransaction */, - null /* finishTransaction */, taskInfo, leash, wct); - mTransaction.apply(); - mTaskViewTransitions.startInstantTransition(TRANSIT_CHANGE, wct); - } - - /** - * Moves the current task in TaskView out of the view and back to fullscreen. - */ - public void moveToFullscreen() { - if (mTaskToken == null) return; - mShellExecutor.execute(() -> { - WindowContainerTransaction wct = new WindowContainerTransaction(); - wct.setWindowingMode(mTaskToken, WINDOWING_MODE_UNDEFINED); - wct.setAlwaysOnTop(mTaskToken, false); - mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, false); - mTaskViewTransitions.moveTaskViewToFullscreen(wct, this); - if (mListener != null) { - // Task is being "removed" from the clients perspective - mListener.onTaskRemovalStarted(mTaskInfo.taskId); - } - }); - } - - private void prepareActivityOptions(ActivityOptions options, Rect launchBounds) { - final Binder launchCookie = new Binder(); - mShellExecutor.execute(() -> { - mTaskOrganizer.setPendingLaunchCookieListener(launchCookie, this); - }); - options.setLaunchBounds(launchBounds); - options.setLaunchCookie(launchCookie); - options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW); - options.setRemoveWithTaskOrganizer(true); - } - - /** * Release this container if it is initialized. */ public void release() { @@ -309,8 +172,8 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { private void performRelease() { mShellExecutor.execute(() -> { - if (mTaskViewTransitions != null) { - mTaskViewTransitions.removeTaskView(this); + if (mTaskViewController != null) { + mTaskViewController.unregisterTaskView(this); } mTaskOrganizer.removeListener(this); resetTaskInfo(); @@ -364,7 +227,7 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { @Override public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { - if (isUsingShellTransitions()) { + if (mTaskViewController.isUsingShellTransitions()) { mPendingInfo = taskInfo; if (mTaskNotFound) { // If we were already notified by shell transit that we don't have the @@ -484,8 +347,8 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { // Nothing to update, task is not yet available return; } - if (isUsingShellTransitions()) { - mTaskViewTransitions.setTaskViewVisible(this, true /* visible */); + if (mTaskViewController.isUsingShellTransitions()) { + mTaskViewController.setTaskViewVisible(this, true /* visible */); return; } // Reparent the task when this surface is created @@ -497,56 +360,6 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { } /** - * Sets the window bounds to {@code boundsOnScreen}. - * Call when view position or size has changed. Can also be called before the animation when - * the final bounds are known. - * Do not call during the animation. - * - * @param boundsOnScreen the on screen bounds of the surface view. - */ - public void setWindowBounds(Rect boundsOnScreen) { - if (mTaskToken == null) { - return; - } - - if (isUsingShellTransitions()) { - mShellExecutor.execute(() -> { - // Sync Transactions can't operate simultaneously with shell transition collection. - mTaskViewTransitions.setTaskBounds(this, boundsOnScreen); - }); - return; - } - - WindowContainerTransaction wct = new WindowContainerTransaction(); - wct.setBounds(mTaskToken, boundsOnScreen); - mSyncQueue.queue(wct); - } - - /** - * Call to remove the task from window manager. This task will not appear in recents. - */ - void removeTask() { - if (mTaskToken == null) { - if (Flags.enableTaskViewControllerCleanup()) { - // We don't have a task yet. Only clean up the controller - mTaskViewTransitions.removeTaskView(this); - } else { - // Call to remove task before we have one, do nothing - Slog.w(TAG, "Trying to remove a task that was never added? (no taskToken)"); - } - return; - } - // Cache it to avoid NPE and make sure to remove it from recents history. - // mTaskToken can be cleared in onTaskVanished() when the task is removed. - final WindowContainerToken taskToken = mTaskToken; - mShellExecutor.execute(() -> { - WindowContainerTransaction wct = new WindowContainerTransaction(); - wct.removeTask(taskToken); - mTaskViewTransitions.closeTaskView(wct, this); - }); - } - - /** * Sets a region of the task to inset to allow for a caption bar. * * @param captionInsets the rect for the insets in screen coordinates. @@ -583,8 +396,8 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { return; } - if (isUsingShellTransitions()) { - mTaskViewTransitions.setTaskViewVisible(this, false /* visible */); + if (mTaskViewController.isUsingShellTransitions()) { + mTaskViewController.setTaskViewVisible(this, false /* visible */); return; } @@ -604,15 +417,16 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { } } + void notifyTaskRemovalStarted(@NonNull ActivityManager.RunningTaskInfo taskInfo) { + if (mListener == null) return; + final int taskId = taskInfo.taskId; + mListenerExecutor.execute(() -> mListener.onTaskRemovalStarted(taskId)); + } + /** Notifies listeners of a task being removed and stops intercepting back presses on it. */ private void handleAndNotifyTaskRemoval(ActivityManager.RunningTaskInfo taskInfo) { if (taskInfo != null) { - if (mListener != null) { - final int taskId = taskInfo.taskId; - mListenerExecutor.execute(() -> { - mListener.onTaskRemovalStarted(taskId); - }); - } + notifyTaskRemovalStarted(taskInfo); mTaskViewBase.onTaskVanished(taskInfo); } } @@ -651,9 +465,7 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { handleAndNotifyTaskRemoval(pendingInfo); // Make sure the task is removed - WindowContainerTransaction wct = new WindowContainerTransaction(); - wct.removeTask(pendingInfo.token); - mTaskViewTransitions.closeTaskView(wct, this); + mTaskViewController.removeTaskView(this, pendingInfo.token); } resetTaskInfo(); } @@ -681,72 +493,23 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { resetTaskInfo(); } - void prepareOpenAnimation(final boolean newTask, - @NonNull SurfaceControl.Transaction startTransaction, - @NonNull SurfaceControl.Transaction finishTransaction, - ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash, - WindowContainerTransaction wct) { - prepareOpenAnimationInternal(newTask, startTransaction, finishTransaction, taskInfo, leash, - wct); - } - - private TaskViewRepository.TaskViewState getState() { - return mTaskViewTransitions.getRepository().byTaskView(this); - } - - private void prepareOpenAnimationInternal(final boolean newTask, - SurfaceControl.Transaction startTransaction, - SurfaceControl.Transaction finishTransaction, - ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash, - WindowContainerTransaction wct) { + /** + * Prepare this taskview to open {@param taskInfo}. + * @return The bounds of the task or {@code null} on failure (surface is destroyed) + */ + Rect prepareOpen(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { mPendingInfo = null; mTaskInfo = taskInfo; mTaskToken = mTaskInfo.token; mTaskLeash = leash; - if (mSurfaceCreated) { - // Surface is ready, so just reparent the task to this surface control - startTransaction.reparent(mTaskLeash, mSurfaceControl) - .show(mTaskLeash); - // Also reparent on finishTransaction since the finishTransaction will reparent back - // to its "original" parent by default. - Rect boundsOnScreen = mTaskViewBase.getCurrentBoundsOnScreen(); - if (finishTransaction != null) { - finishTransaction.reparent(mTaskLeash, mSurfaceControl) - .setPosition(mTaskLeash, 0, 0) - // TODO: maybe once b/280900002 is fixed this will be unnecessary - .setWindowCrop(mTaskLeash, boundsOnScreen.width(), boundsOnScreen.height()); - } - if (TaskViewTransitions.useRepo()) { - final TaskViewRepository.TaskViewState state = getState(); - if (state != null) { - state.mBounds.set(boundsOnScreen); - state.mVisible = true; - } - } else { - mTaskViewTransitions.updateBoundsState(this, boundsOnScreen); - mTaskViewTransitions.updateVisibilityState(this, true /* visible */); - } - wct.setBounds(mTaskToken, boundsOnScreen); - applyCaptionInsetsIfNeeded(); - } else { - // The surface has already been destroyed before the task has appeared, - // so go ahead and hide the task entirely - wct.setHidden(mTaskToken, true /* hidden */); - mTaskViewTransitions.updateVisibilityState(this, false /* visible */); - // listener callback is below - } - if (newTask) { - mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, true /* intercept */); - } - - if (mTaskInfo.taskDescription != null) { - int backgroundColor = mTaskInfo.taskDescription.getBackgroundColor(); - mTaskViewBase.setResizeBgColor(startTransaction, backgroundColor); + if (!mSurfaceCreated) { + return null; } + return mTaskViewBase.getCurrentBoundsOnScreen(); + } - // After the embedded task has appeared, set it to non-trimmable. This is important - // to prevent recents from trimming and removing the embedded task. - wct.setTaskTrimmableFromRecents(taskInfo.token, false /* isTrimmableFromRecents */); + /** Notify that the associated task has appeared. This will call appropriate listeners. */ + void notifyAppeared(final boolean newTask) { mTaskViewBase.onTaskAppeared(mTaskInfo, mTaskLeash); if (mListener != null) { final int taskId = mTaskInfo.taskId; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java index 0cbb7bd14e6f..6c90a9060523 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java @@ -16,6 +16,8 @@ package com.android.wm.shell.taskview; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_OPEN; @@ -25,7 +27,14 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.ActivityOptions; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.content.pm.LauncherApps; +import android.content.pm.ShortcutInfo; import android.graphics.Rect; +import android.os.Binder; import android.os.IBinder; import android.util.ArrayMap; import android.util.Slog; @@ -33,11 +42,14 @@ import android.view.SurfaceControl; import android.view.WindowManager; import android.window.TransitionInfo; import android.window.TransitionRequestInfo; +import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import androidx.annotation.VisibleForTesting; import com.android.wm.shell.Flags; +import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.shared.TransitionUtil; import com.android.wm.shell.transition.Transitions; @@ -45,11 +57,12 @@ import java.util.ArrayList; import java.util.Map; import java.util.Objects; import java.util.WeakHashMap; +import java.util.concurrent.Executor; /** * Handles Shell Transitions that involve TaskView tasks. */ -public class TaskViewTransitions implements Transitions.TransitionHandler { +public class TaskViewTransitions implements Transitions.TransitionHandler, TaskViewController { static final String TAG = "TaskViewTransitions"; /** @@ -65,6 +78,12 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { private final ArrayList<PendingTransition> mPending = new ArrayList<>(); private final Transitions mTransitions; private final boolean[] mRegistered = new boolean[]{false}; + private final ShellTaskOrganizer mTaskOrganizer; + private final Executor mShellExecutor; + private final SyncTransactionQueue mSyncQueue; + + /** A temp transaction used for quick things. */ + private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); /** * TaskView makes heavy use of startTransition. Only one shell-initiated transition can be @@ -96,8 +115,12 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { } } - public TaskViewTransitions(Transitions transitions, TaskViewRepository repository) { + public TaskViewTransitions(Transitions transitions, TaskViewRepository repository, + ShellTaskOrganizer taskOrganizer, SyncTransactionQueue syncQueue) { mTransitions = transitions; + mTaskOrganizer = taskOrganizer; + mShellExecutor = taskOrganizer.getExecutor(); + mSyncQueue = syncQueue; if (useRepo()) { mTaskViews = null; } else if (Flags.enableTaskViewControllerCleanup()) { @@ -111,7 +134,8 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { // TODO(210041388): register here once we have an explicit ordering mechanism. } - static boolean useRepo() { + /** @return whether the shared taskview repository is being used. */ + public static boolean useRepo() { return Flags.taskViewRepository() || Flags.enableBubbleAnything(); } @@ -119,7 +143,8 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { return mTaskViewRepo; } - void addTaskView(TaskViewTaskController tv) { + @Override + public void registerTaskView(TaskViewTaskController tv) { synchronized (mRegistered) { if (!mRegistered[0]) { mRegistered[0] = true; @@ -133,7 +158,8 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { } } - void removeTaskView(TaskViewTaskController tv) { + @Override + public void unregisterTaskView(TaskViewTaskController tv) { if (useRepo()) { mTaskViewRepo.remove(tv); } else { @@ -142,27 +168,12 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { // Note: Don't unregister handler since this is a singleton with lifetime bound to Shell } - boolean isEnabled() { + @Override + public boolean isUsingShellTransitions() { return mTransitions.isRegistered(); } /** - * Looks through the pending transitions for a closing transaction that matches the provided - * `taskView`. - * - * @param taskView the pending transition should be for this. - */ - private PendingTransition findPendingCloseTransition(TaskViewTaskController taskView) { - for (int i = mPending.size() - 1; i >= 0; --i) { - if (mPending.get(i).mTaskView != taskView) continue; - if (TransitionUtil.isClosingType(mPending.get(i).mType)) { - return mPending.get(i); - } - } - return null; - } - - /** * Starts a transition outside of the handler associated with {@link TaskViewTransitions}. */ public void startInstantTransition(@WindowManager.TransitionType int type, @@ -264,6 +275,82 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { return findTaskView(taskInfo) != null; } + private void prepareActivityOptions(ActivityOptions options, Rect launchBounds, + @NonNull TaskViewTaskController destination) { + final Binder launchCookie = new Binder(); + mShellExecutor.execute(() -> { + mTaskOrganizer.setPendingLaunchCookieListener(launchCookie, destination); + }); + options.setLaunchBounds(launchBounds); + options.setLaunchCookie(launchCookie); + options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW); + options.setRemoveWithTaskOrganizer(true); + } + + @Override + public void startShortcutActivity(@NonNull TaskViewTaskController destination, + @NonNull ShortcutInfo shortcut, @NonNull ActivityOptions options, + @Nullable Rect launchBounds) { + prepareActivityOptions(options, launchBounds, destination); + final Context context = destination.getContext(); + if (isUsingShellTransitions()) { + mShellExecutor.execute(() -> { + final WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.startShortcut(context.getPackageName(), shortcut, options.toBundle()); + startTaskView(wct, destination, options.getLaunchCookie()); + }); + return; + } + try { + LauncherApps service = context.getSystemService(LauncherApps.class); + service.startShortcut(shortcut, null /* sourceBounds */, options.toBundle()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void startActivity(@NonNull TaskViewTaskController destination, + @NonNull PendingIntent pendingIntent, @Nullable Intent fillInIntent, + @NonNull ActivityOptions options, @Nullable Rect launchBounds) { + prepareActivityOptions(options, launchBounds, destination); + if (isUsingShellTransitions()) { + mShellExecutor.execute(() -> { + WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.sendPendingIntent(pendingIntent, fillInIntent, options.toBundle()); + startTaskView(wct, destination, options.getLaunchCookie()); + }); + return; + } + try { + pendingIntent.send(destination.getContext(), 0 /* code */, fillInIntent, + null /* onFinished */, null /* handler */, null /* requiredPermission */, + options.toBundle()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void startRootTask(@NonNull TaskViewTaskController destination, + ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash, + @Nullable WindowContainerTransaction wct) { + if (wct == null) { + wct = new WindowContainerTransaction(); + } + // This method skips the regular flow where an activity task is launched as part of a new + // transition in taskview and then transition is intercepted using the launchcookie. + // The task here is already created and running, it just needs to be reparented, resized + // and tracked correctly inside taskview. Which is done by calling + // prepareOpenAnimationInternal() and then manually enqueuing the resulting window container + // transaction. + prepareOpenAnimation(destination, true /* newTask */, mTransaction /* startTransaction */, + null /* finishTransaction */, taskInfo, leash, wct); + mTransaction.apply(); + mTransitions.startTransition(TRANSIT_CHANGE, wct, null); + } + + @VisibleForTesting void startTaskView(@NonNull WindowContainerTransaction wct, @NonNull TaskViewTaskController taskView, @NonNull IBinder launchCookie) { updateVisibilityState(taskView, true /* visible */); @@ -271,30 +358,53 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { startNextTransition(); } - void closeTaskView(@NonNull WindowContainerTransaction wct, - @NonNull TaskViewTaskController taskView) { + @Override + public void removeTaskView(@NonNull TaskViewTaskController taskView, + @Nullable WindowContainerToken taskToken) { + final WindowContainerToken token = taskToken != null ? taskToken : taskView.getTaskToken(); + if (token == null) { + // We don't have a task yet, so just clean up records + if (!Flags.enableTaskViewControllerCleanup()) { + // Call to remove task before we have one, do nothing + Slog.w(TAG, "Trying to remove a task that was never added? (no taskToken)"); + return; + } + unregisterTaskView(taskView); + return; + } + final WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.removeTask(token); updateVisibilityState(taskView, false /* visible */); - mPending.add(new PendingTransition(TRANSIT_CLOSE, wct, taskView, null /* cookie */)); - startNextTransition(); + mShellExecutor.execute(() -> { + mPending.add(new PendingTransition(TRANSIT_CLOSE, wct, taskView, null /* cookie */)); + startNextTransition(); + }); } - void moveTaskViewToFullscreen(@NonNull WindowContainerTransaction wct, - @NonNull TaskViewTaskController taskView) { - mPending.add(new PendingTransition(TRANSIT_CHANGE, wct, taskView, null /* cookie */)); - startNextTransition(); + @Override + public void moveTaskViewToFullscreen(@NonNull TaskViewTaskController taskView) { + final WindowContainerToken taskToken = taskView.getTaskToken(); + if (taskToken == null) return; + final WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.setWindowingMode(taskToken, WINDOWING_MODE_UNDEFINED); + wct.setAlwaysOnTop(taskToken, false); + mShellExecutor.execute(() -> { + mTaskOrganizer.setInterceptBackPressedOnTaskRoot(taskToken, false); + mPending.add(new PendingTransition(TRANSIT_CHANGE, wct, taskView, null /* cookie */)); + startNextTransition(); + taskView.notifyTaskRemovalStarted(taskView.getTaskInfo()); + }); } - /** Starts a new transition to make the given {@code taskView} visible. */ + @Override public void setTaskViewVisible(TaskViewTaskController taskView, boolean visible) { setTaskViewVisible(taskView, visible, false /* reorder */); } /** - * Starts a new transition to make the given {@code taskView} visible and optionally change - * the task order. + * Starts a new transition to make the given {@code taskView} visible and optionally + * reordering it. * - * @param taskView the task view which the visibility is being changed for - * @param visible the new visibility of the task view * @param reorder whether to reorder the task or not. If this is {@code true}, the task will * be reordered as per the given {@code visible}. For {@code visible = true}, * task will be reordered to top. For {@code visible = false}, task will be @@ -359,7 +469,26 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { state.mVisible = visible; } - void setTaskBounds(TaskViewTaskController taskView, Rect boundsOnScreen) { + @Override + public void setTaskBounds(TaskViewTaskController taskView, Rect boundsOnScreen) { + if (taskView.getTaskToken() == null) { + return; + } + + if (isUsingShellTransitions()) { + mShellExecutor.execute(() -> { + // Sync Transactions can't operate simultaneously with shell transition collection. + setTaskBoundsInTransition(taskView, boundsOnScreen); + }); + return; + } + + WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.setBounds(taskView.getTaskToken(), boundsOnScreen); + mSyncQueue.queue(wct); + } + + private void setTaskBoundsInTransition(TaskViewTaskController taskView, Rect boundsOnScreen) { final TaskViewRepository.TaskViewState state = useRepo() ? mTaskViewRepo.byTaskView(taskView) : mTaskViews.get(taskView); @@ -476,7 +605,7 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { } } if (wct == null) wct = new WindowContainerTransaction(); - tv.prepareOpenAnimation(taskIsNew, startTransaction, finishTransaction, + prepareOpenAnimation(tv, taskIsNew, startTransaction, finishTransaction, chg.getTaskInfo(), chg.getLeash(), wct); changesHandled++; } else if (chg.getMode() == TRANSIT_CHANGE) { @@ -510,4 +639,60 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { startNextTransition(); return true; } + + @VisibleForTesting + void prepareOpenAnimation(TaskViewTaskController taskView, + final boolean newTask, + SurfaceControl.Transaction startTransaction, + SurfaceControl.Transaction finishTransaction, + ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash, + WindowContainerTransaction wct) { + final Rect boundsOnScreen = taskView.prepareOpen(taskInfo, leash); + if (boundsOnScreen != null) { + final SurfaceControl tvSurface = taskView.getSurfaceControl(); + // Surface is ready, so just reparent the task to this surface control + startTransaction.reparent(leash, tvSurface) + .show(leash); + // Also reparent on finishTransaction since the finishTransaction will reparent back + // to its "original" parent by default. + if (finishTransaction != null) { + finishTransaction.reparent(leash, tvSurface) + .setPosition(leash, 0, 0) + // TODO: maybe once b/280900002 is fixed this will be unnecessary + .setWindowCrop(leash, boundsOnScreen.width(), boundsOnScreen.height()); + } + if (useRepo()) { + final TaskViewRepository.TaskViewState state = mTaskViewRepo.byTaskView(taskView); + if (state != null) { + state.mBounds.set(boundsOnScreen); + state.mVisible = true; + } + } else { + updateBoundsState(taskView, boundsOnScreen); + updateVisibilityState(taskView, true /* visible */); + } + wct.setBounds(taskInfo.token, boundsOnScreen); + taskView.applyCaptionInsetsIfNeeded(); + } else { + // The surface has already been destroyed before the task has appeared, + // so go ahead and hide the task entirely + wct.setHidden(taskInfo.token, true /* hidden */); + updateVisibilityState(taskView, false /* visible */); + // listener callback is below + } + if (newTask) { + mTaskOrganizer.setInterceptBackPressedOnTaskRoot(taskInfo.token, true /* intercept */); + } + + if (taskInfo.taskDescription != null) { + int backgroundColor = taskInfo.taskDescription.getBackgroundColor(); + taskView.setResizeBgColor(startTransaction, backgroundColor); + } + + // After the embedded task has appeared, set it to non-trimmable. This is important + // to prevent recents from trimming and removing the embedded task. + wct.setTaskTrimmableFromRecents(taskInfo.token, false /* isTrimmableFromRecents */); + + taskView.notifyAppeared(newTask); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java index e61929fef312..2133275cde61 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java @@ -17,13 +17,14 @@ package com.android.wm.shell.transition; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.view.WindowManager.TRANSIT_PIP; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; -import static com.android.wm.shell.shared.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR; -import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED; import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA; import static com.android.wm.shell.shared.TransitionUtil.isOpeningMode; +import static com.android.wm.shell.shared.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR; +import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED; import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN; import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE; import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED; @@ -36,6 +37,7 @@ import android.view.SurfaceControl; import android.window.TransitionInfo; import com.android.internal.protolog.ProtoLog; +import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.keyguard.KeyguardTransitionHandler; import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.protolog.ShellProtoLogGroup; @@ -54,6 +56,7 @@ public class MixedTransitionHelper { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animating a mixed transition for " + "entering PIP while Split-Screen is foreground."); TransitionInfo.Change pipChange = null; + TransitionInfo.Change pipActivityChange = null; TransitionInfo.Change wallpaper = null; final TransitionInfo everythingElse = subCopy(info, TRANSIT_TO_BACK, true /* changes */); @@ -68,6 +71,13 @@ public class MixedTransitionHelper { pipChange = change; // going backwards, so remove-by-index is fine. everythingElse.getChanges().remove(i); + } else if (change.getTaskInfo() == null && change.getParent() != null + && pipChange != null && change.getParent().equals(pipChange.getContainer())) { + // Cache the PiP activity if it's a target and cached pip task change is its parent; + // note that we are bottom-to-top, so if such activity has a task + // that is also a target, then it must have been cached already as pipChange. + pipActivityChange = change; + everythingElse.getChanges().remove(i); } else if (isHomeOpening(change)) { homeIsOpening = true; } else if (isWallpaper(change)) { @@ -138,9 +148,19 @@ public class MixedTransitionHelper { } } - pipHandler.setEnterAnimationType(ANIM_TYPE_ALPHA); - pipHandler.startEnterAnimation(pipChange, startTransaction, finishTransaction, - finishCB); + if (PipUtils.isPip2ExperimentEnabled()) { + TransitionInfo pipInfo = subCopy(info, TRANSIT_PIP, false /* withChanges */); + pipInfo.getChanges().add(pipChange); + if (pipActivityChange != null) { + pipInfo.getChanges().add(pipActivityChange); + } + pipHandler.startAnimation(mixed.mTransition, pipInfo, startTransaction, + finishTransaction, finishCB); + } else { + pipHandler.setEnterAnimationType(ANIM_TYPE_ALPHA); + pipHandler.startEnterAnimation(pipChange, startTransaction, finishTransaction, + finishCB); + } // make a new finishTransaction because pip's startEnterAnimation "consumes" it so // we need a separate one to send over to launcher. SurfaceControl.Transaction otherFinishT = new SurfaceControl.Transaction(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecorViewModel.java index 0d75e659d95c..7948eadb28f4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecorViewModel.java @@ -110,9 +110,6 @@ public abstract class CarWindowDecorViewModel SurfaceControl taskSurface, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { - if (!shouldShowWindowDecor(taskInfo)) { - return false; - } createWindowDecoration(taskInfo, taskSurface, startT, finishT); return true; } @@ -125,12 +122,9 @@ public abstract class CarWindowDecorViewModel return; } - if (!shouldShowWindowDecor(taskInfo)) { - destroyWindowDecoration(taskInfo); - return; - } - - decoration.relayout(taskInfo, decoration.mHasGlobalFocus, decoration.mExclusionRegion); + final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + decoration.relayout(taskInfo, t, t, + /* isCaptionVisible= */ shouldShowWindowDecor(taskInfo)); } @Override @@ -221,7 +215,8 @@ public abstract class CarWindowDecorViewModel mWindowDecorViewHostSupplier, new ButtonClickListener(taskInfo)); mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration); - windowDecoration.relayout(taskInfo, startT, finishT); + windowDecoration.relayout(taskInfo, startT, finishT, + /* isCaptionVisible= */ shouldShowWindowDecor(taskInfo)); } private class ButtonClickListener implements View.OnClickListener { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecoration.java index 1ca82d23c830..39437845301e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CarWindowDecoration.java @@ -20,14 +20,17 @@ import static android.view.InsetsSource.FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.content.Context; +import android.graphics.Insets; import android.graphics.Rect; import android.graphics.Region; import android.view.InsetsState; import android.view.SurfaceControl; import android.view.View; +import android.view.WindowInsets; import android.window.WindowContainerTransaction; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; @@ -44,6 +47,7 @@ public class CarWindowDecoration extends WindowDecoration<WindowDecorLinearLayou private WindowDecorLinearLayout mRootView; private @ShellBackgroundThread final ShellExecutor mBgExecutor; private final View.OnClickListener mClickListener; + private final RelayoutResult<WindowDecorLinearLayout> mResult = new RelayoutResult<>(); CarWindowDecoration( Context context, @@ -71,26 +75,32 @@ public class CarWindowDecoration extends WindowDecoration<WindowDecorLinearLayou @SuppressLint("MissingPermission") void relayout(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { + relayout(taskInfo, startT, finishT, /* isCaptionVisible= */ true); + } + + @SuppressLint("MissingPermission") + void relayout(ActivityManager.RunningTaskInfo taskInfo, + SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, + boolean isCaptionVisible) { final WindowContainerTransaction wct = new WindowContainerTransaction(); RelayoutParams relayoutParams = new RelayoutParams(); - RelayoutResult<WindowDecorLinearLayout> outResult = new RelayoutResult<>(); updateRelayoutParams(relayoutParams, taskInfo, - mDisplayController.getInsetsState(taskInfo.displayId)); + mDisplayController.getInsetsState(taskInfo.displayId), isCaptionVisible); - relayout(relayoutParams, startT, finishT, wct, mRootView, outResult); + relayout(relayoutParams, startT, finishT, wct, mRootView, mResult); // After this line, mTaskInfo is up-to-date and should be used instead of taskInfo mBgExecutor.execute(() -> mTaskOrganizer.applyTransaction(wct)); - if (outResult.mRootView == null) { + if (mResult.mRootView == null) { // This means something blocks the window decor from showing, e.g. the task is hidden. // Nothing is set up in this case including the decoration surface. return; } - if (mRootView != outResult.mRootView) { - mRootView = outResult.mRootView; - setupRootView(outResult.mRootView, mClickListener); + if (mRootView != mResult.mRootView) { + mRootView = mResult.mRootView; + setupRootView(mResult.mRootView, mClickListener); } } @@ -108,18 +118,31 @@ public class CarWindowDecoration extends WindowDecoration<WindowDecorLinearLayou private void updateRelayoutParams( RelayoutParams relayoutParams, ActivityManager.RunningTaskInfo taskInfo, - InsetsState displayInsetsState) { + @Nullable InsetsState displayInsetsState, + boolean isCaptionVisible) { relayoutParams.reset(); relayoutParams.mRunningTaskInfo = taskInfo; // todo(b/382071404): update to car specific UI relayoutParams.mLayoutResId = R.layout.caption_window_decor; relayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height; - relayoutParams.mIsCaptionVisible = mIsStatusBarVisible && !mIsKeyguardVisibleAndOccluded; - relayoutParams.mCaptionTopPadding = 0; + relayoutParams.mIsCaptionVisible = + isCaptionVisible && mIsStatusBarVisible && !mIsKeyguardVisibleAndOccluded; + if (displayInsetsState != null) { + relayoutParams.mCaptionTopPadding = getTopPadding( + taskInfo.getConfiguration().windowConfiguration.getBounds(), + displayInsetsState); + } relayoutParams.mInsetSourceFlags |= FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR; relayoutParams.mApplyStartTransactionOnDraw = true; } + private static int getTopPadding(Rect taskBounds, @NonNull InsetsState insetsState) { + Insets systemDecor = insetsState.calculateInsets(taskBounds, + WindowInsets.Type.systemBars() & ~WindowInsets.Type.captionBar(), + false /* ignoreVisibility */); + return systemDecor.top; + } + /** * Sets up listeners when a new root view is created. */ diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleViewInfoTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleViewInfoTest.kt index eeb83df48ab5..417b43a9c6c0 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleViewInfoTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleViewInfoTest.kt @@ -46,6 +46,7 @@ import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.taskview.TaskView +import com.android.wm.shell.taskview.TaskViewRepository import com.android.wm.shell.taskview.TaskViewTransitions import com.android.wm.shell.transition.Transitions import com.google.common.truth.Truth.assertThat @@ -137,6 +138,7 @@ class BubbleViewInfoTest : ShellTestCase() { mainExecutor, mock<Handler>(), bgExecutor, + mock<TaskViewRepository>(), mock<TaskViewTransitions>(), mock<Transitions>(), mock<SyncTransactionQueue>(), diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/CloseDesktopTaskTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/CloseDesktopTaskTransitionHandlerTest.kt index 04f9ada8a9d7..03aad1c5c721 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/CloseDesktopTaskTransitionHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/CloseDesktopTaskTransitionHandlerTest.kt @@ -21,6 +21,7 @@ import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WindowingMode +import android.os.Handler import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.SurfaceControl @@ -52,6 +53,7 @@ class CloseDesktopTaskTransitionHandlerTest : ShellTestCase() { @Mock lateinit var testExecutor: ShellExecutor @Mock lateinit var closingTaskLeash: SurfaceControl + @Mock lateinit var mockHandler: Handler private val transactionSupplier = Supplier { mock<SurfaceControl.Transaction>() } @@ -65,6 +67,7 @@ class CloseDesktopTaskTransitionHandlerTest : ShellTestCase() { testExecutor, testExecutor, transactionSupplier, + mockHandler, ) } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipAlphaAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipAlphaAnimatorTest.java index 9cc18ffdaed7..607e6a450883 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipAlphaAnimatorTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipAlphaAnimatorTest.java @@ -19,6 +19,8 @@ package com.android.wm.shell.pip2.animation; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; @@ -33,6 +35,7 @@ import android.view.SurfaceControl; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.wm.shell.R; import com.android.wm.shell.pip2.PipSurfaceTransactionHelper; import org.junit.Before; @@ -48,6 +51,8 @@ import org.mockito.MockitoAnnotations; @TestableLooper.RunWithLooper @RunWith(AndroidTestingRunner.class) public class PipAlphaAnimatorTest { + private static final float TEST_CORNER_RADIUS = 1f; + private static final float TEST_SHADOW_RADIUS = 2f; @Mock private Context mMockContext; @@ -55,7 +60,9 @@ public class PipAlphaAnimatorTest { @Mock private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mMockFactory; - @Mock private SurfaceControl.Transaction mMockTransaction; + @Mock private SurfaceControl.Transaction mMockAnimateTransaction; + @Mock private SurfaceControl.Transaction mMockStartTransaction; + @Mock private SurfaceControl.Transaction mMockFinishTransaction; @Mock private Runnable mMockStartCallback; @@ -69,9 +76,15 @@ public class PipAlphaAnimatorTest { MockitoAnnotations.initMocks(this); when(mMockContext.getResources()).thenReturn(mMockResources); when(mMockResources.getInteger(anyInt())).thenReturn(0); - when(mMockFactory.getTransaction()).thenReturn(mMockTransaction); - when(mMockTransaction.setAlpha(any(SurfaceControl.class), anyFloat())) - .thenReturn(mMockTransaction); + when(mMockFactory.getTransaction()).thenReturn(mMockAnimateTransaction); + when(mMockResources.getDimensionPixelSize(R.dimen.pip_corner_radius)) + .thenReturn((int) TEST_CORNER_RADIUS); + when(mMockResources.getDimensionPixelSize(R.dimen.pip_shadow_radius)) + .thenReturn((int) TEST_SHADOW_RADIUS); + + prepareTransaction(mMockAnimateTransaction); + prepareTransaction(mMockStartTransaction); + prepareTransaction(mMockFinishTransaction); mTestLeash = new SurfaceControl.Builder() .setContainerLayer() @@ -82,8 +95,8 @@ public class PipAlphaAnimatorTest { @Test public void setAnimationStartCallback_fadeInAnimator_callbackStartCallback() { - mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockTransaction, - PipAlphaAnimator.FADE_IN); + mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction, + mMockFinishTransaction, PipAlphaAnimator.FADE_IN); mPipAlphaAnimator.setAnimationStartCallback(mMockStartCallback); mPipAlphaAnimator.setAnimationEndCallback(mMockEndCallback); @@ -98,8 +111,8 @@ public class PipAlphaAnimatorTest { @Test public void setAnimationEndCallback_fadeInAnimator_callbackStartAndEndCallback() { - mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockTransaction, - PipAlphaAnimator.FADE_IN); + mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction, + mMockFinishTransaction, PipAlphaAnimator.FADE_IN); mPipAlphaAnimator.setAnimationStartCallback(mMockStartCallback); mPipAlphaAnimator.setAnimationEndCallback(mMockEndCallback); @@ -109,36 +122,98 @@ public class PipAlphaAnimatorTest { }); verify(mMockStartCallback).run(); - verify(mMockStartCallback).run(); + verify(mMockEndCallback).run(); + } + + @Test + public void onAnimationStart_setCornerAndShadowRadii() { + mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction, + mMockFinishTransaction, PipAlphaAnimator.FADE_IN); + mPipAlphaAnimator.setSurfaceControlTransactionFactory(mMockFactory); + + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + mPipAlphaAnimator.start(); + mPipAlphaAnimator.pause(); + }); + + verify(mMockStartTransaction, atLeastOnce()) + .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS)); + verify(mMockStartTransaction, atLeastOnce()) + .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS)); + } + + @Test + public void onAnimationUpdate_setCornerAndShadowRadii() { + mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction, + mMockFinishTransaction, PipAlphaAnimator.FADE_IN); + mPipAlphaAnimator.setSurfaceControlTransactionFactory(mMockFactory); + + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + mPipAlphaAnimator.start(); + mPipAlphaAnimator.pause(); + }); + + verify(mMockAnimateTransaction, atLeastOnce()) + .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS)); + verify(mMockAnimateTransaction, atLeastOnce()) + .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS)); + } + + @Test + public void onAnimationEnd_setCornerAndShadowRadii() { + mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction, + mMockFinishTransaction, PipAlphaAnimator.FADE_IN); + mPipAlphaAnimator.setSurfaceControlTransactionFactory(mMockFactory); + + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + mPipAlphaAnimator.start(); + mPipAlphaAnimator.end(); + }); + + verify(mMockFinishTransaction, atLeastOnce()) + .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS)); + verify(mMockFinishTransaction, atLeastOnce()) + .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS)); } @Test public void onAnimationEnd_fadeInAnimator_leashVisibleAtEnd() { - mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockTransaction, - PipAlphaAnimator.FADE_IN); + mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction, + mMockFinishTransaction, PipAlphaAnimator.FADE_IN); mPipAlphaAnimator.setSurfaceControlTransactionFactory(mMockFactory); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { mPipAlphaAnimator.start(); - clearInvocations(mMockTransaction); + clearInvocations(mMockAnimateTransaction); mPipAlphaAnimator.end(); }); - verify(mMockTransaction).setAlpha(mTestLeash, 1.0f); + verify(mMockAnimateTransaction).setAlpha(mTestLeash, 1.0f); } @Test public void onAnimationEnd_fadeOutAnimator_leashInvisibleAtEnd() { - mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockTransaction, - PipAlphaAnimator.FADE_OUT); + mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction, + mMockFinishTransaction, PipAlphaAnimator.FADE_OUT); mPipAlphaAnimator.setSurfaceControlTransactionFactory(mMockFactory); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { mPipAlphaAnimator.start(); - clearInvocations(mMockTransaction); + clearInvocations(mMockAnimateTransaction); mPipAlphaAnimator.end(); }); - verify(mMockTransaction).setAlpha(mTestLeash, 0f); + verify(mMockAnimateTransaction).setAlpha(mTestLeash, 0f); + } + + + // set up transaction chaining + private void prepareTransaction(SurfaceControl.Transaction tx) { + when(tx.setAlpha(any(SurfaceControl.class), anyFloat())) + .thenReturn(tx); + when(tx.setCornerRadius(any(SurfaceControl.class), anyFloat())) + .thenReturn(tx); + when(tx.setShadowRadius(any(SurfaceControl.class), anyFloat())) + .thenReturn(tx); } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java index aef44a40fa0f..bd857c7dcd45 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java @@ -111,7 +111,7 @@ public class PipSchedulerTest { mRootTaskDisplayAreaOrganizer); mPipScheduler.setPipTransitionController(mMockPipTransitionController); mPipScheduler.setSurfaceControlTransactionFactory(mMockFactory); - mPipScheduler.setPipAlphaAnimatorSupplier((context, leash, tx, direction) -> + mPipScheduler.setPipAlphaAnimatorSupplier((context, leash, startTx, finishTx, direction) -> mMockAlphaAnimator); SurfaceControl testLeash = new SurfaceControl.Builder() diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java index 66636c56bb64..6ac34d736f6f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java @@ -165,10 +165,11 @@ public class TaskViewTest extends ShellTestCase { doReturn(true).when(mTransitions).isRegistered(); } mTaskViewRepository = new TaskViewRepository(); - mTaskViewTransitions = spy(new TaskViewTransitions(mTransitions, mTaskViewRepository)); + mTaskViewTransitions = spy(new TaskViewTransitions(mTransitions, mTaskViewRepository, + mOrganizer, mSyncQueue)); mTaskViewTaskController = new TaskViewTaskController(mContext, mOrganizer, mTaskViewTransitions, mSyncQueue); - mTaskView = new TaskView(mContext, mTaskViewTaskController); + mTaskView = new TaskView(mContext, mTaskViewTransitions, mTaskViewTaskController); mTaskView.setHandler(mViewHandler); mTaskView.setListener(mExecutor, mViewListener); } @@ -182,7 +183,7 @@ public class TaskViewTest extends ShellTestCase { @Test public void testSetPendingListener_throwsException() { - TaskView taskView = new TaskView(mContext, + TaskView taskView = new TaskView(mContext, mTaskViewTransitions, new TaskViewTaskController(mContext, mOrganizer, mTaskViewTransitions, mSyncQueue)); taskView.setListener(mExecutor, mViewListener); try { @@ -326,7 +327,7 @@ public class TaskViewTest extends ShellTestCase { public void testOnNewTask_noSurface() { assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS); WindowContainerTransaction wct = new WindowContainerTransaction(); - mTaskViewTaskController.prepareOpenAnimation(true /* newTask */, + mTaskViewTransitions.prepareOpenAnimation(mTaskViewTaskController, true /* newTask */, new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct); @@ -354,7 +355,7 @@ public class TaskViewTest extends ShellTestCase { assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS); mTaskView.surfaceCreated(mock(SurfaceHolder.class)); WindowContainerTransaction wct = new WindowContainerTransaction(); - mTaskViewTaskController.prepareOpenAnimation(true /* newTask */, + mTaskViewTransitions.prepareOpenAnimation(mTaskViewTaskController, true /* newTask */, new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct); @@ -366,7 +367,7 @@ public class TaskViewTest extends ShellTestCase { public void testSurfaceCreated_withTask() { assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS); WindowContainerTransaction wct = new WindowContainerTransaction(); - mTaskViewTaskController.prepareOpenAnimation(true /* newTask */, + mTaskViewTransitions.prepareOpenAnimation(mTaskViewTaskController, true /* newTask */, new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct); mTaskView.surfaceCreated(mock(SurfaceHolder.class)); @@ -374,7 +375,7 @@ public class TaskViewTest extends ShellTestCase { verify(mViewListener).onInitialized(); verify(mTaskViewTransitions).setTaskViewVisible(eq(mTaskViewTaskController), eq(true)); - mTaskViewTaskController.prepareOpenAnimation(false /* newTask */, + mTaskViewTransitions.prepareOpenAnimation(mTaskViewTaskController, false /* newTask */, new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct); @@ -396,7 +397,7 @@ public class TaskViewTest extends ShellTestCase { assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS); SurfaceHolder sh = mock(SurfaceHolder.class); WindowContainerTransaction wct = new WindowContainerTransaction(); - mTaskViewTaskController.prepareOpenAnimation(true /* newTask */, + mTaskViewTransitions.prepareOpenAnimation(mTaskViewTaskController, true /* newTask */, new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct); mTaskView.surfaceCreated(sh); @@ -414,7 +415,7 @@ public class TaskViewTest extends ShellTestCase { public void testOnReleased() { assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS); WindowContainerTransaction wct = new WindowContainerTransaction(); - mTaskViewTaskController.prepareOpenAnimation(true /* newTask */, + mTaskViewTransitions.prepareOpenAnimation(mTaskViewTaskController, true /* newTask */, new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct); mTaskView.surfaceCreated(mock(SurfaceHolder.class)); @@ -423,14 +424,14 @@ public class TaskViewTest extends ShellTestCase { verify(mOrganizer).removeListener(eq(mTaskViewTaskController)); verify(mViewListener).onReleased(); assertThat(mTaskView.isInitialized()).isFalse(); - verify(mTaskViewTransitions).removeTaskView(eq(mTaskViewTaskController)); + verify(mTaskViewTransitions).unregisterTaskView(eq(mTaskViewTaskController)); } @Test public void testOnTaskVanished() { assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS); WindowContainerTransaction wct = new WindowContainerTransaction(); - mTaskViewTaskController.prepareOpenAnimation(true /* newTask */, + mTaskViewTransitions.prepareOpenAnimation(mTaskViewTaskController, true /* newTask */, new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct); mTaskView.surfaceCreated(mock(SurfaceHolder.class)); @@ -443,7 +444,7 @@ public class TaskViewTest extends ShellTestCase { public void testOnBackPressedOnTaskRoot() { assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS); WindowContainerTransaction wct = new WindowContainerTransaction(); - mTaskViewTaskController.prepareOpenAnimation(true /* newTask */, + mTaskViewTransitions.prepareOpenAnimation(mTaskViewTaskController, true /* newTask */, new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct); mTaskViewTaskController.onBackPressedOnTaskRoot(mTaskInfo); @@ -455,7 +456,7 @@ public class TaskViewTest extends ShellTestCase { public void testSetOnBackPressedOnTaskRoot() { assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS); WindowContainerTransaction wct = new WindowContainerTransaction(); - mTaskViewTaskController.prepareOpenAnimation(true /* newTask */, + mTaskViewTransitions.prepareOpenAnimation(mTaskViewTaskController, true /* newTask */, new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct); verify(mOrganizer).setInterceptBackPressedOnTaskRoot(eq(mTaskInfo.token), eq(true)); @@ -524,7 +525,7 @@ public class TaskViewTest extends ShellTestCase { // Make the task available WindowContainerTransaction wct = mock(WindowContainerTransaction.class); - mTaskViewTaskController.startRootTask(mTaskInfo, mLeash, wct); + mTaskViewTransitions.startRootTask(mTaskViewTaskController, mTaskInfo, mLeash, wct); // Bounds got set verify(wct).setBounds(any(WindowContainerToken.class), eq(bounds)); @@ -564,7 +565,7 @@ public class TaskViewTest extends ShellTestCase { // Make the task available / start prepareOpen WindowContainerTransaction wct = mock(WindowContainerTransaction.class); - mTaskViewTaskController.prepareOpenAnimation(true /* newTask */, + mTaskViewTransitions.prepareOpenAnimation(mTaskViewTaskController, true /* newTask */, new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct); @@ -594,7 +595,7 @@ public class TaskViewTest extends ShellTestCase { // Task is available, but the surface was never created WindowContainerTransaction wct = mock(WindowContainerTransaction.class); - mTaskViewTaskController.prepareOpenAnimation(true /* newTask */, + mTaskViewTransitions.prepareOpenAnimation(mTaskViewTaskController, true /* newTask */, new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct); @@ -619,7 +620,7 @@ public class TaskViewTest extends ShellTestCase { assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS); mTaskView.removeTask(); - verify(mTaskViewTransitions, never()).closeTaskView(any(), any()); + assertFalse(mTaskViewTransitions.hasPending()); } @Test @@ -628,14 +629,14 @@ public class TaskViewTest extends ShellTestCase { mTaskView.surfaceCreated(mock(SurfaceHolder.class)); WindowContainerTransaction wct = new WindowContainerTransaction(); - mTaskViewTaskController.prepareOpenAnimation(true /* newTask */, + mTaskViewTransitions.prepareOpenAnimation(mTaskViewTaskController, true /* newTask */, new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct); verify(mViewListener).onTaskCreated(eq(mTaskInfo.taskId), any()); mTaskView.removeTask(); - verify(mTaskViewTransitions).closeTaskView(any(), eq(mTaskViewTaskController)); + verify(mTaskViewTransitions).removeTaskView(eq(mTaskViewTaskController), any()); } @Test @@ -646,7 +647,7 @@ public class TaskViewTest extends ShellTestCase { mTaskViewTaskController.onTaskAppeared(mTaskInfo, mLeash); assertNull(mTaskViewTaskController.getTaskInfo()); - verify(mTaskViewTransitions).closeTaskView(any(), eq(mTaskViewTaskController)); + verify(mTaskViewTransitions).removeTaskView(eq(mTaskViewTaskController), any()); } @Test @@ -655,7 +656,7 @@ public class TaskViewTest extends ShellTestCase { mTaskViewTaskController.onTaskAppeared(mTaskInfo, mLeash); assertEquals(mTaskInfo, mTaskViewTaskController.getPendingInfo()); - verify(mTaskViewTransitions, never()).closeTaskView(any(), any()); + verify(mTaskViewTransitions, never()).removeTaskView(any(), any()); } @Test @@ -671,7 +672,7 @@ public class TaskViewTest extends ShellTestCase { mTaskView.surfaceCreated(mock(SurfaceHolder.class)); reset(mOrganizer); WindowContainerTransaction wct = new WindowContainerTransaction(); - mTaskViewTaskController.prepareOpenAnimation(true /* newTask */, + mTaskViewTransitions.prepareOpenAnimation(mTaskViewTaskController, true /* newTask */, new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct); mTaskView.onComputeInternalInsets(new ViewTreeObserver.InternalInsetsInfo()); @@ -688,7 +689,7 @@ public class TaskViewTest extends ShellTestCase { mTaskView.surfaceCreated(mock(SurfaceHolder.class)); WindowContainerTransaction wct = new WindowContainerTransaction(); - mTaskViewTaskController.prepareOpenAnimation(true /* newTask */, + mTaskViewTransitions.prepareOpenAnimation(mTaskViewTaskController, true /* newTask */, new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct); reset(mOrganizer); @@ -706,7 +707,7 @@ public class TaskViewTest extends ShellTestCase { public void testReleaseInOnTaskRemoval_noNPE() { mTaskViewTaskController = spy(new TaskViewTaskController(mContext, mOrganizer, mTaskViewTransitions, mSyncQueue)); - mTaskView = new TaskView(mContext, mTaskViewTaskController); + mTaskView = new TaskView(mContext, mTaskViewTransitions, mTaskViewTaskController); mTaskView.setListener(mExecutor, new TaskView.Listener() { @Override public void onTaskRemovalStarted(int taskId) { @@ -715,7 +716,7 @@ public class TaskViewTest extends ShellTestCase { }); WindowContainerTransaction wct = new WindowContainerTransaction(); - mTaskViewTaskController.prepareOpenAnimation(true /* newTask */, + mTaskViewTransitions.prepareOpenAnimation(mTaskViewTaskController, true /* newTask */, new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct); mTaskView.surfaceCreated(mock(SurfaceHolder.class)); @@ -763,7 +764,7 @@ public class TaskViewTest extends ShellTestCase { @Test public void testOnAppeared_setsTrimmableTask() { WindowContainerTransaction wct = new WindowContainerTransaction(); - mTaskViewTaskController.prepareOpenAnimation(true /* newTask */, + mTaskViewTransitions.prepareOpenAnimation(mTaskViewTaskController, true /* newTask */, new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct); @@ -773,11 +774,11 @@ public class TaskViewTest extends ShellTestCase { @Test public void testMoveToFullscreen_callsTaskRemovalStarted() { WindowContainerTransaction wct = new WindowContainerTransaction(); - mTaskViewTaskController.prepareOpenAnimation(true /* newTask */, + mTaskViewTransitions.prepareOpenAnimation(mTaskViewTaskController, true /* newTask */, new SurfaceControl.Transaction(), new SurfaceControl.Transaction(), mTaskInfo, mLeash, wct); mTaskView.surfaceCreated(mock(SurfaceHolder.class)); - mTaskViewTaskController.moveToFullscreen(); + mTaskViewTransitions.moveTaskViewToFullscreen(mTaskViewTaskController); verify(mViewListener).onTaskRemovalStarted(eq(mTaskInfo.taskId)); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java index 5f6f18f82fb4..326f11e300fd 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java @@ -44,7 +44,9 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; import com.android.wm.shell.Flags; +import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.transition.Transitions; import org.junit.Before; @@ -56,6 +58,7 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executor; import platform.test.runner.parameterized.ParameterizedAndroidJunit4; import platform.test.runner.parameterized.Parameters; @@ -82,6 +85,12 @@ public class TaskViewTransitionsTest extends ShellTestCase { ActivityManager.RunningTaskInfo mTaskInfo; @Mock WindowContainerToken mToken; + @Mock + ShellTaskOrganizer mOrganizer; + @Mock + SyncTransactionQueue mSyncQueue; + + Executor mExecutor = command -> command.run(); TaskViewRepository mTaskViewRepository; TaskViewTransitions mTaskViewTransitions; @@ -104,9 +113,12 @@ public class TaskViewTransitionsTest extends ShellTestCase { mTaskInfo.taskDescription = mock(ActivityManager.TaskDescription.class); mTaskViewRepository = new TaskViewRepository(); - mTaskViewTransitions = spy(new TaskViewTransitions(mTransitions, mTaskViewRepository)); - mTaskViewTransitions.addTaskView(mTaskViewTaskController); + when(mOrganizer.getExecutor()).thenReturn(mExecutor); + mTaskViewTransitions = spy(new TaskViewTransitions(mTransitions, mTaskViewRepository, + mOrganizer, mSyncQueue)); + mTaskViewTransitions.registerTaskView(mTaskViewTaskController); when(mTaskViewTaskController.getTaskInfo()).thenReturn(mTaskInfo); + when(mTaskViewTaskController.getTaskToken()).thenReturn(mToken); } @Test @@ -212,7 +224,7 @@ public class TaskViewTransitionsTest extends ShellTestCase { @Test public void testSetTaskVisibility_taskRemoved_noNPE() { - mTaskViewTransitions.removeTaskView(mTaskViewTaskController); + mTaskViewTransitions.unregisterTaskView(mTaskViewTaskController); assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS); @@ -221,7 +233,7 @@ public class TaskViewTransitionsTest extends ShellTestCase { @Test public void testSetTaskBounds_taskRemoved_noNPE() { - mTaskViewTransitions.removeTaskView(mTaskViewTaskController); + mTaskViewTransitions.unregisterTaskView(mTaskViewTaskController); assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS); diff --git a/packages/SettingsLib/ActionButtonsPreference/res/color/settingslib_expressive_actionbutton_background.xml b/packages/SettingsLib/ActionButtonsPreference/res/color/settingslib_expressive_actionbutton_background.xml new file mode 100644 index 000000000000..ec9ee2211259 --- /dev/null +++ b/packages/SettingsLib/ActionButtonsPreference/res/color/settingslib_expressive_actionbutton_background.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:color="@color/settingslib_materialColorSurface"/> + <item android:state_checked="true" android:color="?attr/colorContainerChecked"/> + <item android:state_checkable="true" android:color="?attr/colorContainerUnchecked"/> + <item android:color="@color/settingslib_materialColorPrimaryContainer" /> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/ActionButtonsPreference/res/color/settingslib_expressive_actionbutton_content_color.xml b/packages/SettingsLib/ActionButtonsPreference/res/color/settingslib_expressive_actionbutton_content_color.xml new file mode 100644 index 000000000000..0488cbaead22 --- /dev/null +++ b/packages/SettingsLib/ActionButtonsPreference/res/color/settingslib_expressive_actionbutton_content_color.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:alpha="@dimen/material_emphasis_disabled" android:color="?attr/colorOnSurface"/> + <item android:state_checkable="true" android:state_checked="true" + android:color="?attr/colorOnContainerChecked"/> + <item android:state_checkable="true" android:color="?attr/colorOnContainerUnchecked"/> + <item android:color="@color/settingslib_materialColorOnPrimaryContainer"/> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/ActionButtonsPreference/res/values-v35/styles_expressive.xml b/packages/SettingsLib/ActionButtonsPreference/res/values-v35/styles_expressive.xml index fd8cecb8536e..267c9f65e104 100644 --- a/packages/SettingsLib/ActionButtonsPreference/res/values-v35/styles_expressive.xml +++ b/packages/SettingsLib/ActionButtonsPreference/res/values-v35/styles_expressive.xml @@ -17,9 +17,14 @@ <resources> <style name="SettingsLibActionButton.Expressive" parent="SettingsLibButtonStyle.Expressive.Tonal"> - <item name="android:backgroundTint">@color/settingslib_materialColorPrimaryContainer</item> - <item name="iconTint">@color/settingslib_materialColorOnPrimaryContainer</item> - <item name="iconGravity">textTop</item> + <item name="android:backgroundTint">@color/settingslib_expressive_actionbutton_background</item> + <item name="android:textColor">@color/settingslib_expressive_actionbutton_content_color</item> + <item name="android:insetTop">@dimen/settingslib_expressive_space_none</item> + <item name="android:insetBottom">@dimen/settingslib_expressive_space_none</item> + <item name="iconTint">@color/settingslib_expressive_actionbutton_content_color</item> + <item name="iconSize">@dimen/settingslib_expressive_space_small4</item> + <item name="iconPadding">@dimen/settingslib_expressive_space_none</item>" + <item name="iconGravity">textStart</item> </style> <style name="SettingsLibActionButton.Expressive.Label" parent=""> diff --git a/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java b/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java index 601e001f48c2..0027d632319b 100644 --- a/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java +++ b/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java @@ -549,7 +549,7 @@ public class ActionButtonsPreference extends Preference implements GroupSectionD ((MaterialButton) mButton).setIcon(mIcon); } mButton.setEnabled(mIsEnabled); - mActionLayout.setOnClickListener(mListener); + mButton.setOnClickListener(mListener); mActionLayout.setEnabled(mIsEnabled); mActionLayout.setContentDescription(mText); } else { diff --git a/packages/SettingsLib/BannerMessagePreference/Android.bp b/packages/SettingsLib/BannerMessagePreference/Android.bp index 3f671b9e7b10..77e2cc735895 100644 --- a/packages/SettingsLib/BannerMessagePreference/Android.bp +++ b/packages/SettingsLib/BannerMessagePreference/Android.bp @@ -14,12 +14,16 @@ android_library { "SettingsLintDefaults", ], - srcs: ["src/**/*.java"], + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], resource_dirs: ["res"], static_libs: [ - "androidx.preference_preference", + "SettingsLibButtonPreference", "SettingsLibSettingsTheme", + "androidx.preference_preference", ], sdk_version: "system_current", diff --git a/packages/SettingsLib/BannerMessagePreference/res/color/settingslib_banner_button_background_high.xml b/packages/SettingsLib/BannerMessagePreference/res/color/settingslib_banner_button_background_high.xml new file mode 100644 index 000000000000..d113b547bf3e --- /dev/null +++ b/packages/SettingsLib/BannerMessagePreference/res/color/settingslib_banner_button_background_high.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:alpha="@dimen/material_emphasis_disabled_background" android:color="@color/settingslib_colorBackgroundLevel_high"/> + <item android:state_checked="true" android:color="?attr/colorContainerChecked"/> + <item android:state_checkable="true" android:color="?attr/colorContainerUnchecked"/> + <item android:color="@color/settingslib_colorBackgroundLevel_high" /> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/BannerMessagePreference/res/color/settingslib_banner_button_background_low.xml b/packages/SettingsLib/BannerMessagePreference/res/color/settingslib_banner_button_background_low.xml new file mode 100644 index 000000000000..cb89d9a18fc2 --- /dev/null +++ b/packages/SettingsLib/BannerMessagePreference/res/color/settingslib_banner_button_background_low.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:alpha="@dimen/material_emphasis_disabled_background" android:color="@color/settingslib_colorBackgroundLevel_low"/> + <item android:state_checked="true" android:color="?attr/colorContainerChecked"/> + <item android:state_checkable="true" android:color="?attr/colorContainerUnchecked"/> + <item android:color="@color/settingslib_colorBackgroundLevel_low" /> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/BannerMessagePreference/res/color/settingslib_banner_button_background_medium.xml b/packages/SettingsLib/BannerMessagePreference/res/color/settingslib_banner_button_background_medium.xml new file mode 100644 index 000000000000..f820c352632d --- /dev/null +++ b/packages/SettingsLib/BannerMessagePreference/res/color/settingslib_banner_button_background_medium.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:alpha="@dimen/material_emphasis_disabled_background" android:color="@color/settingslib_colorBackgroundLevel_medium"/> + <item android:state_checked="true" android:color="?attr/colorContainerChecked"/> + <item android:state_checkable="true" android:color="?attr/colorContainerUnchecked"/> + <item android:color="@color/settingslib_colorBackgroundLevel_medium" /> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/BannerMessagePreference/res/color/settingslib_banner_button_background_normal.xml b/packages/SettingsLib/BannerMessagePreference/res/color/settingslib_banner_button_background_normal.xml new file mode 100644 index 000000000000..8037a8bb75be --- /dev/null +++ b/packages/SettingsLib/BannerMessagePreference/res/color/settingslib_banner_button_background_normal.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:alpha="@dimen/material_emphasis_disabled_background" android:color="?attr/colorOnSurface"/> + <item android:state_checked="true" android:color="?attr/colorContainerChecked"/> + <item android:state_checkable="true" android:color="?attr/colorContainerUnchecked"/> + <item android:color="?attr/colorContainer" /> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/BannerMessagePreference/res/drawable-v31/settingslib_card_background.xml b/packages/SettingsLib/BannerMessagePreference/res/drawable-v31/settingslib_card_background.xml index 072eb5873ce5..3f806e1574b7 100644 --- a/packages/SettingsLib/BannerMessagePreference/res/drawable-v31/settingslib_card_background.xml +++ b/packages/SettingsLib/BannerMessagePreference/res/drawable-v31/settingslib_card_background.xml @@ -16,6 +16,6 @@ --> <shape xmlns:android="http://schemas.android.com/apk/res/android"> - <solid android:color="?android:attr/background" /> + <solid android:color="@android:color/white" /> <corners android:radius="28dp"/> </shape>
\ No newline at end of file diff --git a/packages/SettingsLib/BannerMessagePreference/res/drawable-v35/settingslib_expressive_card_background.xml b/packages/SettingsLib/BannerMessagePreference/res/drawable-v35/settingslib_expressive_card_background.xml new file mode 100644 index 000000000000..a677a66f86e7 --- /dev/null +++ b/packages/SettingsLib/BannerMessagePreference/res/drawable-v35/settingslib_expressive_card_background.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/settingslib_materialColorSurfaceBright" /> + <corners android:radius="28dp"/> +</shape>
\ No newline at end of file diff --git a/packages/SettingsLib/BannerMessagePreference/res/layout-v31/settingslib_banner_message.xml b/packages/SettingsLib/BannerMessagePreference/res/layout-v31/settingslib_banner_message.xml index 9d53e39c7bf8..ca596d89fab6 100644 --- a/packages/SettingsLib/BannerMessagePreference/res/layout-v31/settingslib_banner_message.xml +++ b/packages/SettingsLib/BannerMessagePreference/res/layout-v31/settingslib_banner_message.xml @@ -15,85 +15,92 @@ limitations under the License. --> -<com.android.settingslib.widget.BannerMessageView - xmlns:android="http://schemas.android.com/apk/res/android" +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical" - style="@style/Banner.Preference.SettingsLib"> + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" + android:paddingStart="?android:attr/listPreferredItemPaddingStart"> - <RelativeLayout - android:id="@+id/top_row" + <com.android.settingslib.widget.BannerMessageView + android:id="@+id/banner_background" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingBottom="8dp" - android:orientation="horizontal"> + android:orientation="vertical" + style="@style/Banner.Preference.SettingsLib"> - <ImageView - android:id="@+id/banner_icon" - android:layout_width="24dp" - android:layout_height="24dp" - android:layout_alignParentStart="true" - android:importantForAccessibility="no" /> - - <ImageButton - android:id="@+id/banner_dismiss_btn" - android:layout_width="wrap_content" + <RelativeLayout + android:id="@+id/top_row" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:src="@drawable/settingslib_ic_cross" - android:layout_alignParentEnd="true" - android:contentDescription="@string/accessibility_banner_message_dismiss" - style="@style/Banner.Dismiss.SettingsLib" /> - </RelativeLayout> + android:paddingBottom="8dp" + android:orientation="horizontal"> - <TextView - android:id="@+id/banner_title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="start" - android:textAlignment="viewStart" - android:paddingTop="0dp" - android:paddingBottom="4dp" - android:textAppearance="@style/Banner.Title.SettingsLib"/> + <ImageView + android:id="@+id/banner_icon" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_alignParentStart="true" + android:importantForAccessibility="no" /> - <TextView - android:id="@+id/banner_subtitle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="start" - android:textAlignment="viewStart" - android:paddingTop="0dp" - android:paddingBottom="4dp" - android:textAppearance="@style/Banner.Subtitle.SettingsLib" - android:visibility="gone"/> + <ImageButton + android:id="@+id/banner_dismiss_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/settingslib_ic_cross" + android:layout_alignParentEnd="true" + android:contentDescription="@string/accessibility_banner_message_dismiss" + style="@style/Banner.Dismiss.SettingsLib" /> + </RelativeLayout> - <TextView - android:id="@+id/banner_summary" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="start" - android:textAlignment="viewStart" - android:paddingTop="4dp" - android:paddingBottom="8dp" - android:textAppearance="@style/Banner.Summary.SettingsLib"/> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" - android:minHeight="8dp" - android:gravity="end"> + <TextView + android:id="@+id/banner_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="start" + android:textAlignment="viewStart" + android:paddingTop="0dp" + android:paddingBottom="4dp" + android:textAppearance="@style/Banner.Title.SettingsLib"/> - <Button - android:id="@+id/banner_negative_btn" + <TextView + android:id="@+id/banner_subtitle" android:layout_width="wrap_content" android:layout_height="wrap_content" - style="@style/Banner.ButtonText.SettingsLib"/> + android:layout_gravity="start" + android:textAlignment="viewStart" + android:paddingTop="0dp" + android:paddingBottom="4dp" + android:textAppearance="@style/Banner.Subtitle.SettingsLib" + android:visibility="gone"/> - <Button - android:id="@+id/banner_positive_btn" + <TextView + android:id="@+id/banner_summary" android:layout_width="wrap_content" android:layout_height="wrap_content" - style="@style/Banner.ButtonText.SettingsLib"/> - </LinearLayout> -</com.android.settingslib.widget.BannerMessageView>
\ No newline at end of file + android:layout_gravity="start" + android:textAlignment="viewStart" + android:paddingTop="4dp" + android:paddingBottom="8dp" + android:textAppearance="@style/Banner.Summary.SettingsLib"/> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:minHeight="8dp" + android:gravity="end"> + + <Button + android:id="@+id/banner_negative_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/Banner.ButtonText.SettingsLib"/> + + <Button + android:id="@+id/banner_positive_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/Banner.ButtonText.SettingsLib"/> + </LinearLayout> + </com.android.settingslib.widget.BannerMessageView> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SettingsLib/BannerMessagePreference/res/layout-v35/settingslib_expressive_banner_message.xml b/packages/SettingsLib/BannerMessagePreference/res/layout-v35/settingslib_expressive_banner_message.xml new file mode 100644 index 000000000000..b10ef6e77ec7 --- /dev/null +++ b/packages/SettingsLib/BannerMessagePreference/res/layout-v35/settingslib_expressive_banner_message.xml @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" + android:paddingStart="?android:attr/listPreferredItemPaddingStart"> + + <com.android.settingslib.widget.BannerMessageView + android:id="@+id/banner_background" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + style="@style/Banner.Preference.SettingsLib.Expressive"> + + <RelativeLayout + android:id="@+id/top_row" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentStart="true" + android:layout_marginEnd="@dimen/settingslib_expressive_space_medium4" + android:orientation="vertical"> + <TextView + android:id="@+id/banner_header" + android:layout_width="match_parent" + android:layout_height="wrap_content" + style="@style/Banner.Header.SettingsLib.Expressive"/> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + + <ImageView + android:id="@+id/banner_icon" + android:layout_width="@dimen/settingslib_expressive_space_small3" + android:layout_height="@dimen/settingslib_expressive_space_small3" + android:layout_gravity="center_vertical" + android:importantForAccessibility="no" + android:scaleType="fitCenter" /> + + <TextView + android:id="@+id/banner_title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + style="@style/Banner.Title.SettingsLib.Expressive" /> + </LinearLayout> + + <TextView + android:id="@+id/banner_subtitle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + style="@style/Banner.Subtitle.SettingsLib.Expressive"/> + </LinearLayout> + + <ImageButton + android:id="@+id/banner_dismiss_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/Banner.Dismiss.SettingsLib.Expressive" /> + </RelativeLayout> + + <TextView + android:id="@+id/banner_summary" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/Banner.Summary.SettingsLib.Expressive"/> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:id="@+id/banner_buttons_frame" + android:paddingTop="@dimen/settingslib_expressive_space_extrasmall6" + android:orientation="horizontal"> + + <com.google.android.material.button.MaterialButton + android:id="@+id/banner_negative_btn" + android:layout_weight="1" + style="@style/Banner.NegativeButton.SettingsLib.Expressive"/> + <Space + android:layout_width="@dimen/settingslib_expressive_space_extrasmall4" + android:layout_height="@dimen/settingslib_expressive_space_small1"/> + <com.google.android.material.button.MaterialButton + android:id="@+id/banner_positive_btn" + android:layout_weight="1" + style="@style/Banner.PositiveButton.SettingsLib.Expressive"/> + </LinearLayout> + </com.android.settingslib.widget.BannerMessageView> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SettingsLib/BannerMessagePreference/res/layout/settingslib_banner_message_preference_group.xml b/packages/SettingsLib/BannerMessagePreference/res/layout/settingslib_banner_message_preference_group.xml new file mode 100644 index 000000000000..c74e39187562 --- /dev/null +++ b/packages/SettingsLib/BannerMessagePreference/res/layout/settingslib_banner_message_preference_group.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:baselineAligned="false" + android:id="@+id/banner_group_layout" + android:importantForAccessibility="no" + android:filterTouchesWhenObscured="false" + android:orientation="horizontal"> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml b/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml index fede44feb090..5909f8e0f85e 100644 --- a/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml +++ b/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml @@ -24,9 +24,7 @@ <item name="android:paddingTop">20dp</item> <item name="android:paddingBottom">8dp</item> <item name="android:layout_marginTop">8dp</item> - <item name="android:layout_marginStart">16dp</item> <item name="android:layout_marginBottom">8dp</item> - <item name="android:layout_marginEnd">16dp</item> <item name="android:background">@drawable/settingslib_card_background</item> </style> diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-v35/styles_expressive.xml b/packages/SettingsLib/BannerMessagePreference/res/values-v35/styles_expressive.xml new file mode 100644 index 000000000000..b864311bf9b7 --- /dev/null +++ b/packages/SettingsLib/BannerMessagePreference/res/values-v35/styles_expressive.xml @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> + +<resources> + + <style name="Banner.Preference.SettingsLib.Expressive"> + <item name="android:padding">@dimen/settingslib_expressive_space_small1</item> + <item name="android:background">@drawable/settingslib_expressive_card_background</item> + </style> + + <style name="Banner.Header.SettingsLib.Expressive" + parent=""> + <item name="android:textAlignment">viewStart</item> + <item name="android:paddingBottom">@dimen/settingslib_expressive_space_extrasmall4</item> + <item name="android:textAppearance">@style/TextAppearance.SettingsLib.LabelMedium</item> + <item name="android:textColor">?android:attr/textColorPrimary</item> + </style> + + <style name="Banner.Title.SettingsLib.Expressive" + parent=""> + <item name="android:layout_gravity">start</item> + <item name="android:layout_marginLeft">@dimen/settingslib_expressive_space_extrasmall4</item> + <item name="android:textAlignment">viewStart</item> + <item name="android:textAppearance">@style/TextAppearance.SettingsLib.TitleLarge.Emphasized</item> + <item name="android:textColor">?android:attr/textColorPrimary</item> + </style> + + <style name="Banner.Subtitle.SettingsLib.Expressive" + parent=""> + <item name="android:layout_gravity">start</item> + <item name="android:textAlignment">viewStart</item> + <item name="android:paddingTop">@dimen/settingslib_expressive_space_extrasmall4</item> + <item name="android:textAppearance">@style/TextAppearance.SettingsLib.BodyMedium</item> + <item name="android:textColor">?android:attr/textColorPrimary</item> + </style> + + <style name="Banner.Summary.SettingsLib.Expressive" + parent=""> + <item name="android:layout_gravity">start</item> + <item name="android:textAlignment">viewStart</item> + <item name="android:paddingTop">@dimen/settingslib_expressive_space_extrasmall6</item> + <item name="android:textAppearance">@style/TextAppearance.SettingsLib.BodyMedium</item> + <item name="android:textColor">?android:attr/textColorPrimary</item> + </style> + + <style name="Banner.Dismiss.SettingsLib.Expressive"> + <item name="android:src">@drawable/settingslib_expressive_icon_cross</item> + <item name="android:layout_alignParentEnd">true</item> + <item name="android:contentDescription">@string/accessibility_banner_message_dismiss</item> + </style> + + <style name="Banner.PositiveButton.SettingsLib.Expressive" + parent="@style/SettingsLibButtonStyle.Expressive.Filled.Extra"> + <item name="android:textColor">?android:attr/textColorPrimaryInverse</item> + <item name="materialSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Small</item> + </style> + + <style name="Banner.NegativeButton.SettingsLib.Expressive" + parent="@style/SettingsLibButtonStyle.Expressive.Outline.Extra"> + <item name="materialSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Small</item> + </style> +</resources> diff --git a/packages/SettingsLib/BannerMessagePreference/res/values/attrs.xml b/packages/SettingsLib/BannerMessagePreference/res/values/attrs.xml index 96634a51de56..86d5f476b0f2 100644 --- a/packages/SettingsLib/BannerMessagePreference/res/values/attrs.xml +++ b/packages/SettingsLib/BannerMessagePreference/res/values/attrs.xml @@ -21,7 +21,18 @@ <enum name="high" value="0"/> <enum name="medium" value="1"/> <enum name="low" value="2"/> + <enum name="normal" value="3"/> </attr> <attr format="string" name="subtitle" /> + <attr format="string" name="bannerHeader" /> + <attr format="integer" name="buttonOrientation" /> + </declare-styleable> + + <declare-styleable name="BannerMessagePreferenceGroup"> + <attr format="string" name="expandKey" /> + <attr format="string" name="expandTitle" /> + <attr format="string" name="collapseKey" /> + <attr format="string" name="collapseTitle" /> + <attr format="reference" name="collapseIcon" /> </declare-styleable> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/BannerMessagePreference/res/values/colors.xml b/packages/SettingsLib/BannerMessagePreference/res/values/colors.xml index 53d72d1eeff7..891def1c610a 100644 --- a/packages/SettingsLib/BannerMessagePreference/res/values/colors.xml +++ b/packages/SettingsLib/BannerMessagePreference/res/values/colors.xml @@ -19,7 +19,9 @@ <color name="banner_background_attention_high">#FFDAD5</color> <!-- red card background --> <color name="banner_background_attention_medium">#F0E3A8</color> <!-- yellow card background --> <color name="banner_background_attention_low">#CFEBC0</color> <!-- green card background --> + <color name="banner_background_attention_normal">@color/settingslib_materialColorSurfaceBright</color> <!-- normal card background --> <color name="banner_accent_attention_high">#BB3322</color> <!-- red accent color --> <color name="banner_accent_attention_medium">#895900</color> <!-- yellow accent color --> <color name="banner_accent_attention_low">#1D7233</color> <!-- green accent color --> + <color name="banner_accent_attention_normal">@color/settingslib_materialColorPrimary</color> <!-- normal accent color --> </resources> diff --git a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java index 10769ecfbe42..60a9ebd6f98b 100644 --- a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java +++ b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java @@ -17,6 +17,7 @@ package com.android.settingslib.widget; import android.content.Context; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.PorterDuff; @@ -29,6 +30,7 @@ import android.view.View; import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.ColorInt; @@ -39,6 +41,8 @@ import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; import com.android.settingslib.widget.preference.banner.R; + +import com.google.android.material.button.MaterialButton; /** * Banner message is a banner displaying important information (permission request, page error etc), * and provide actions for user to address. It requires a user action to be dismissed. @@ -46,22 +50,36 @@ import com.android.settingslib.widget.preference.banner.R; public class BannerMessagePreference extends Preference implements GroupSectionDividerMixin { public enum AttentionLevel { - HIGH(0, R.color.banner_background_attention_high, R.color.banner_accent_attention_high), + HIGH(0, + R.color.banner_background_attention_high, + R.color.banner_accent_attention_high, + R.color.settingslib_banner_button_background_high), MEDIUM(1, - R.color.banner_background_attention_medium, - R.color.banner_accent_attention_medium), - LOW(2, R.color.banner_background_attention_low, R.color.banner_accent_attention_low); + R.color.banner_background_attention_medium, + R.color.banner_accent_attention_medium, + R.color.settingslib_banner_button_background_medium), + LOW(2, + R.color.banner_background_attention_low, + R.color.banner_accent_attention_low, + R.color.settingslib_banner_button_background_low), + NORMAL(3, + R.color.banner_background_attention_normal, + R.color.banner_accent_attention_normal, + R.color.settingslib_banner_button_background_normal); // Corresponds to the enum valye of R.attr.attentionLevel private final int mAttrValue; @ColorRes private final int mBackgroundColorResId; @ColorRes private final int mAccentColorResId; + @ColorRes private final int mButtonBackgroundColorResId; AttentionLevel(int attrValue, @ColorRes int backgroundColorResId, - @ColorRes int accentColorResId) { + @ColorRes int accentColorResId, + @ColorRes int buttonBackgroundColorResId) { mAttrValue = attrValue; mBackgroundColorResId = backgroundColorResId; mAccentColorResId = accentColorResId; + mButtonBackgroundColorResId = buttonBackgroundColorResId; } static AttentionLevel fromAttr(int attrValue) { @@ -80,6 +98,10 @@ public class BannerMessagePreference extends Preference implements GroupSectionD public @ColorRes int getBackgroundColorResId() { return mBackgroundColorResId; } + + public @ColorRes int getButtonBackgroundColorResId() { + return mButtonBackgroundColorResId; + } } private static final String TAG = "BannerPreference"; @@ -95,6 +117,8 @@ public class BannerMessagePreference extends Preference implements GroupSectionD // Default attention level is High. private AttentionLevel mAttentionLevel = AttentionLevel.HIGH; private String mSubtitle; + private String mHeader; + private int mButtonOrientation; public BannerMessagePreference(Context context) { super(context); @@ -119,7 +143,10 @@ public class BannerMessagePreference extends Preference implements GroupSectionD private void init(Context context, AttributeSet attrs) { setSelectable(false); - setLayoutResource(R.layout.settingslib_banner_message); + int resId = SettingsThemeHelper.isExpressiveTheme(context) + ? R.layout.settingslib_expressive_banner_message + : R.layout.settingslib_banner_message; + setLayoutResource(resId); if (IS_AT_LEAST_S) { if (attrs != null) { @@ -130,6 +157,9 @@ public class BannerMessagePreference extends Preference implements GroupSectionD a.getInt(R.styleable.BannerMessagePreference_attentionLevel, 0); mAttentionLevel = AttentionLevel.fromAttr(mAttentionLevelValue); mSubtitle = a.getString(R.styleable.BannerMessagePreference_subtitle); + mHeader = a.getString(R.styleable.BannerMessagePreference_bannerHeader); + mButtonOrientation = a.getInt(R.styleable.BannerMessagePreference_buttonOrientation, + LinearLayout.HORIZONTAL); a.recycle(); } } @@ -142,11 +172,16 @@ public class BannerMessagePreference extends Preference implements GroupSectionD final TextView titleView = (TextView) holder.findViewById(R.id.banner_title); CharSequence title = getTitle(); - titleView.setText(title); - titleView.setVisibility(title == null ? View.GONE : View.VISIBLE); + if (titleView != null) { + titleView.setText(title); + titleView.setVisibility(title == null ? View.GONE : View.VISIBLE); + } final TextView summaryView = (TextView) holder.findViewById(R.id.banner_summary); - summaryView.setText(getSummary()); + if (summaryView != null) { + summaryView.setText(getSummary()); + summaryView.setVisibility(TextUtils.isEmpty(getSummary()) ? View.GONE : View.VISIBLE); + } mPositiveButtonInfo.mButton = (Button) holder.findViewById(R.id.banner_positive_btn); mNegativeButtonInfo.mButton = (Button) holder.findViewById(R.id.banner_negative_btn); @@ -162,8 +197,11 @@ public class BannerMessagePreference extends Preference implements GroupSectionD icon == null ? getContext().getDrawable(R.drawable.ic_warning) : icon); - iconView.setColorFilter( - new PorterDuffColorFilter(accentColor, PorterDuff.Mode.SRC_IN)); + if (mAttentionLevel != AttentionLevel.NORMAL + && !SettingsThemeHelper.isExpressiveTheme(context)) { + iconView.setColorFilter( + new PorterDuffColorFilter(accentColor, PorterDuff.Mode.SRC_IN)); + } } if (IS_AT_LEAST_S) { @@ -171,12 +209,25 @@ public class BannerMessagePreference extends Preference implements GroupSectionD context.getResources().getColor( mAttentionLevel.getBackgroundColorResId(), theme); + @ColorInt final int btnBackgroundColor = + context.getResources().getColor(mAttentionLevel.getButtonBackgroundColorResId(), + theme); + ColorStateList strokeColor = context.getResources().getColorStateList( + mAttentionLevel.getButtonBackgroundColorResId(), theme); + holder.setDividerAllowedAbove(false); holder.setDividerAllowedBelow(false); - holder.itemView.getBackground().setTint(backgroundColor); + View backgroundView = holder.findViewById(R.id.banner_background); + if (backgroundView != null && !SettingsThemeHelper.isExpressiveTheme(context)) { + backgroundView.getBackground().setTint(backgroundColor); + } mPositiveButtonInfo.mColor = accentColor; mNegativeButtonInfo.mColor = accentColor; + if (mAttentionLevel != AttentionLevel.NORMAL) { + mPositiveButtonInfo.mBackgroundColor = btnBackgroundColor; + mNegativeButtonInfo.mStrokeColor = strokeColor; + } mDismissButtonInfo.mButton = (ImageButton) holder.findViewById(R.id.banner_dismiss_btn); mDismissButtonInfo.setUpButton(); @@ -185,6 +236,13 @@ public class BannerMessagePreference extends Preference implements GroupSectionD subtitleView.setText(mSubtitle); subtitleView.setVisibility(mSubtitle == null ? View.GONE : View.VISIBLE); + TextView headerView = (TextView) holder.findViewById(R.id.banner_header); + if (headerView != null) { + headerView.setText(mHeader); + headerView.setVisibility(TextUtils.isEmpty(mHeader) ? View.GONE : View.VISIBLE); + } + + } else { holder.setDividerAllowedAbove(true); holder.setDividerAllowedBelow(true); @@ -192,6 +250,24 @@ public class BannerMessagePreference extends Preference implements GroupSectionD mPositiveButtonInfo.setUpButton(); mNegativeButtonInfo.setUpButton(); + View buttonFrame = holder.findViewById(R.id.banner_buttons_frame); + if (buttonFrame != null) { + buttonFrame.setVisibility( + mPositiveButtonInfo.shouldBeVisible() || mNegativeButtonInfo.shouldBeVisible() + ? View.VISIBLE : View.GONE); + + LinearLayout linearLayout = (LinearLayout) buttonFrame; + if (mButtonOrientation != linearLayout.getOrientation()) { + int childCount = linearLayout.getChildCount(); + //reverse the order of the buttons + for (int i = childCount - 1; i >= 0; i--) { + View child = linearLayout.getChildAt(i); + linearLayout.removeViewAt(i); + linearLayout.addView(child); + } + linearLayout.setOrientation(mButtonOrientation); + } + } } /** @@ -302,6 +378,18 @@ public class BannerMessagePreference extends Preference implements GroupSectionD } /** + * Sets button orientation. + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + public BannerMessagePreference setButtonOrientation(int orientation) { + if (mButtonOrientation != orientation) { + mButtonOrientation = orientation; + notifyChanged(); + } + return this; + } + + /** * Sets the subtitle. */ @RequiresApi(Build.VERSION_CODES.S) @@ -322,6 +410,26 @@ public class BannerMessagePreference extends Preference implements GroupSectionD } /** + * Sets the header. + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + public BannerMessagePreference setHeader(@StringRes int textResId) { + return setHeader(getContext().getString(textResId)); + } + + /** + * Sets the header. + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + public BannerMessagePreference setHeader(String header) { + if (!TextUtils.equals(header, mSubtitle)) { + mHeader = header; + notifyChanged(); + } + return this; + } + + /** * Sets the attention level. This will update the color theme of the preference. */ public BannerMessagePreference setAttentionLevel(AttentionLevel attentionLevel) { @@ -342,13 +450,29 @@ public class BannerMessagePreference extends Preference implements GroupSectionD private View.OnClickListener mListener; private boolean mIsVisible = true; @ColorInt private int mColor; + @ColorInt private int mBackgroundColor; + private ColorStateList mStrokeColor; void setUpButton() { mButton.setText(mText); mButton.setOnClickListener(mListener); + MaterialButton btn = null; + if (mButton instanceof MaterialButton) { + btn = (MaterialButton) mButton; + } + if (IS_AT_LEAST_S) { - mButton.setTextColor(mColor); + if (btn != null && SettingsThemeHelper.isExpressiveTheme(btn.getContext())) { + if (mBackgroundColor != 0) { + btn.setBackgroundColor(mBackgroundColor); + } + if (mStrokeColor != null) { + btn.setStrokeColor(mStrokeColor); + } + } else { + mButton.setTextColor(mColor); + } } if (shouldBeVisible()) { diff --git a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreferenceGroup.kt b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreferenceGroup.kt new file mode 100644 index 000000000000..75455635fca1 --- /dev/null +++ b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreferenceGroup.kt @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2025 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.settingslib.widget + +import android.content.Context +import android.graphics.drawable.Drawable +import android.util.AttributeSet +import android.view.View +import androidx.preference.Preference +import androidx.preference.PreferenceGroup +import androidx.preference.PreferenceViewHolder + +import com.android.settingslib.widget.preference.banner.R + +/** + * Custom PreferenceGroup that allows expanding and collapsing child preferences. + */ +class BannerMessagePreferenceGroup @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 +) : PreferenceGroup(context, attrs, defStyleAttr, defStyleRes), GroupSectionDividerMixin { + + private var isExpanded = false + private var expandPreference: NumberButtonPreference? = null + private var collapsePreference: SectionButtonPreference? = null + private val childPreferences = mutableListOf<BannerMessagePreference>() + private var expandKey: String? = null + private var expandTitle: String? = null + private var collapseKey: String? = null + private var collapseTitle: String? = null + private var collapseIcon: Drawable? = null + var expandContentDescription: Int = 0 + set(value) { + field = value + expandPreference?.btnContentDescription = expandContentDescription + } + + init { + isPersistent = false // This group doesn't store data + layoutResource = R.layout.settingslib_banner_message_preference_group + + initAttributes(context, attrs, defStyleAttr) + } + + override fun addPreference(preference: Preference): Boolean { + if (preference !is BannerMessagePreference) { + return false + } + + if (childPreferences.size >= MAX_CHILDREN) { + return false + } + + childPreferences.add(preference) + return super.addPreference(preference) + } + + override fun removePreference(preference: Preference): Boolean { + if (preference !is BannerMessagePreference) { + return false + } + childPreferences.remove(preference) + return super.removePreference(preference) + } + + override fun onBindViewHolder(holder: PreferenceViewHolder) { + super.onBindViewHolder(holder) + if (childPreferences.size >= MAX_CHILDREN - 1) { + if (expandPreference == null) { + expandPreference = NumberButtonPreference(context).apply { + key = expandKey + title = expandTitle + count = childPreferences.size - 1 + btnContentDescription = expandContentDescription + clickListener = View.OnClickListener { + toggleExpansion() + } + } + super.addPreference(expandPreference!!) + } + if (collapsePreference == null) { + collapsePreference = SectionButtonPreference(context) + .apply { + key = collapseKey + title = collapseTitle + icon = collapseIcon + setOnClickListener { + toggleExpansion() + } + } + super.addPreference(collapsePreference!!) + } + } + updateExpandCollapsePreference() + updateChildrenVisibility() + } + + private fun updateExpandCollapsePreference() { + expandPreference?.isVisible = !isExpanded + collapsePreference?.isVisible = isExpanded + } + + private fun updateChildrenVisibility() { + for (i in 1 until childPreferences.size) { + val child = childPreferences[i] + child.isVisible = isExpanded + } + } + + private fun toggleExpansion() { + isExpanded = !isExpanded + updateExpandCollapsePreference() + updateChildrenVisibility() + } + + private fun initAttributes(context: Context, attrs: AttributeSet?, defStyleAttr: Int) { + context.obtainStyledAttributes( + attrs, + R.styleable.BannerMessagePreferenceGroup, defStyleAttr, 0 + ).apply { + expandKey = getString(R.styleable.BannerMessagePreferenceGroup_expandKey) + expandTitle = getString(R.styleable.BannerMessagePreferenceGroup_expandTitle) + collapseKey = getString(R.styleable.BannerMessagePreferenceGroup_collapseKey) + collapseTitle = getString(R.styleable.BannerMessagePreferenceGroup_collapseTitle) + collapseIcon = getDrawable(R.styleable.BannerMessagePreferenceGroup_collapseIcon) + recycle() + } + } + + companion object { + private const val MAX_CHILDREN = 3 + } +}
\ No newline at end of file diff --git a/packages/SettingsLib/ButtonPreference/Android.bp b/packages/SettingsLib/ButtonPreference/Android.bp index 08dd27fd25ce..a377f312ffbf 100644 --- a/packages/SettingsLib/ButtonPreference/Android.bp +++ b/packages/SettingsLib/ButtonPreference/Android.bp @@ -14,12 +14,15 @@ android_library { "SettingsLintDefaults", ], - srcs: ["src/**/*.java"], + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], resource_dirs: ["res"], static_libs: [ - "androidx.preference_preference", "SettingsLibSettingsTheme", + "androidx.preference_preference", ], sdk_version: "system_current", diff --git a/packages/SettingsLib/ButtonPreference/res/color/settingslib_section_button_background.xml b/packages/SettingsLib/ButtonPreference/res/color/settingslib_section_button_background.xml new file mode 100644 index 000000000000..0972b625d4fd --- /dev/null +++ b/packages/SettingsLib/ButtonPreference/res/color/settingslib_section_button_background.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:alpha="@dimen/material_emphasis_disabled_background" android:color="@color/settingslib_materialColorSurfaceBright"/> + <item android:color="@color/settingslib_materialColorSurfaceBright" /> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/ButtonPreference/res/drawable/settingslib_number_button_background.xml b/packages/SettingsLib/ButtonPreference/res/drawable/settingslib_number_button_background.xml new file mode 100644 index 000000000000..9bf5c430e8e7 --- /dev/null +++ b/packages/SettingsLib/ButtonPreference/res/drawable/settingslib_number_button_background.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/settingslib_materialColorSurfaceBright" /> + <corners android:radius="@dimen/settingslib_expressive_radius_extralarge2"/> +</shape>
\ No newline at end of file diff --git a/packages/SettingsLib/ButtonPreference/res/drawable/settingslib_number_count_background.xml b/packages/SettingsLib/ButtonPreference/res/drawable/settingslib_number_count_background.xml new file mode 100644 index 000000000000..b993811b34f5 --- /dev/null +++ b/packages/SettingsLib/ButtonPreference/res/drawable/settingslib_number_count_background.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/settingslib_materialColorSecondaryContainer" /> + <corners android:radius="100dp"/> +</shape>
\ No newline at end of file diff --git a/packages/SettingsLib/ButtonPreference/res/layout/settingslib_number_button.xml b/packages/SettingsLib/ButtonPreference/res/layout/settingslib_number_button.xml new file mode 100644 index 000000000000..fa13b4125065 --- /dev/null +++ b/packages/SettingsLib/ButtonPreference/res/layout/settingslib_number_button.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingStart="?android:attr/listPreferredItemPaddingStart" + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" + android:paddingVertical="@dimen/settingslib_expressive_space_extrasmall4"> + + <LinearLayout + android:id="@+id/settingslib_number_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingVertical="@dimen/settingslib_expressive_space_small1" + android:paddingHorizontal="@dimen/settingslib_expressive_space_small4" + android:background="@drawable/settingslib_number_button_background"> + <TextView + android:id="@+id/settingslib_number_count" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/SettingsLibNumberButtonStyle.Number"/> + <TextView + android:id="@+id/settingslib_number_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/SettingsLibNumberButtonStyle.Title"/> + </LinearLayout> + +</LinearLayout>
\ No newline at end of file diff --git a/packages/SettingsLib/ButtonPreference/res/layout/settingslib_section_button.xml b/packages/SettingsLib/ButtonPreference/res/layout/settingslib_section_button.xml new file mode 100644 index 000000000000..e7fb572d06dc --- /dev/null +++ b/packages/SettingsLib/ButtonPreference/res/layout/settingslib_section_button.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. +--> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingStart="?android:attr/listPreferredItemPaddingStart" + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" + android:paddingVertical="@dimen/settingslib_expressive_space_extrasmall4"> + + <com.google.android.material.button.MaterialButton + android:id="@+id/settingslib_section_button" + style="@style/SettingsLibSectionButtonStyle.Expressive" /> + +</LinearLayout>
\ No newline at end of file diff --git a/packages/SettingsLib/ButtonPreference/res/values/styles.xml b/packages/SettingsLib/ButtonPreference/res/values/styles.xml index 3963732f7ae4..5208e2004a5f 100644 --- a/packages/SettingsLib/ButtonPreference/res/values/styles.xml +++ b/packages/SettingsLib/ButtonPreference/res/values/styles.xml @@ -30,4 +30,33 @@ <item name="android:textColor">@color/settingslib_btn_colored_text_material</item> <item name="android:background">@drawable/settingslib_btn_colored_material</item> </style> + + <style name="SettingsLibSectionButtonStyle.Expressive" + parent="@style/SettingsLibButtonStyle.Expressive.Filled.Large"> + <item name="android:textColor">?android:attr/textColorPrimary</item> + <item name="backgroundTint">@color/settingslib_section_button_background</item> + <item name="iconTint">?android:attr/textColorPrimary</item> + </style> + + <style name="SettingsLibNumberButtonStyle.Number" + parent=""> + <item name="android:minWidth">@dimen/settingslib_expressive_space_small4</item> + <item name="android:minHeight">@dimen/settingslib_expressive_space_small4</item> + <item name="android:gravity">center</item> + <item name="android:background">@drawable/settingslib_number_count_background</item> + <item name="android:paddingStart">@dimen/settingslib_expressive_radius_extrasmall2</item> + <item name="android:paddingEnd">@dimen/settingslib_expressive_radius_extrasmall2</item> + <item name="android:layout_marginEnd">@dimen/settingslib_expressive_space_extrasmall4</item> + <item name="android:textAppearance">@style/TextAppearance.SettingsLib.TitleMedium</item> + <item name="android:textColor">@color/settingslib_materialColorOnSecondaryContainer</item> + <item name="android:importantForAccessibility">no</item> + </style> + + <style name="SettingsLibNumberButtonStyle.Title" + parent=""> + <item name="android:gravity">center</item> + <item name="android:textAppearance">@style/TextAppearance.SettingsLib.LabelLarge</item> + <item name="android:textColor">@color/settingslib_materialColorOnSurface</item> + <item name="android:importantForAccessibility">no</item> + </style> </resources> diff --git a/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/NumberButtonPreference.kt b/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/NumberButtonPreference.kt new file mode 100644 index 000000000000..a1772d5acdf9 --- /dev/null +++ b/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/NumberButtonPreference.kt @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2025 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.settingslib.widget + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.widget.TextView +import androidx.preference.Preference +import androidx.preference.PreferenceViewHolder + +import com.android.settingslib.widget.preference.button.R + +class NumberButtonPreference @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 +) : Preference(context, attrs, defStyleAttr, defStyleRes), GroupSectionDividerMixin { + + var clickListener: View.OnClickListener? = null + + var count: Int = 0 + set(value) { + field = value + notifyChanged() + } + + var btnContentDescription: Int = 0 + set(value) { + field = value + notifyChanged() + } + + init { + isPersistent = false // This preference doesn't store data + order = Int.MAX_VALUE + layoutResource = R.layout.settingslib_number_button + } + + override fun onBindViewHolder(holder: PreferenceViewHolder) { + super.onBindViewHolder(holder) + holder.isDividerAllowedAbove = false + holder.isDividerAllowedBelow = false + + holder.findViewById(R.id.settingslib_number_button)?.apply { + setOnClickListener(clickListener) + if (btnContentDescription != 0) { + setContentDescription(context.getString(btnContentDescription, count)) + } + } + (holder.findViewById(R.id.settingslib_number_title) as? TextView)?.text = title + + (holder.findViewById(R.id.settingslib_number_count) as? TextView)?.text = "$count" + } +}
\ No newline at end of file diff --git a/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/SectionButtonPreference.kt b/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/SectionButtonPreference.kt new file mode 100644 index 000000000000..b374dea48d21 --- /dev/null +++ b/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/SectionButtonPreference.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2025 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.settingslib.widget + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import androidx.preference.Preference +import androidx.preference.PreferenceViewHolder +import com.android.settingslib.widget.preference.button.R +import com.google.android.material.button.MaterialButton + +/** + * A Preference that displays a button with an optional icon. + */ +class SectionButtonPreference @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 +) : Preference(context, attrs, defStyleAttr, defStyleRes), GroupSectionDividerMixin { + + private var clickListener: ((View) -> Unit)? = null + set(value) { + field = value + notifyChanged() + } + private var button: MaterialButton? = null + init { + isPersistent = false // This preference doesn't store data + order = Int.MAX_VALUE + layoutResource = R.layout.settingslib_section_button + } + + override fun onBindViewHolder(holder: PreferenceViewHolder) { + super.onBindViewHolder(holder) + holder.isDividerAllowedAbove = false + holder.isDividerAllowedBelow = false + + button = holder.findViewById(R.id.settingslib_section_button) as? MaterialButton + button?.apply{ + text = title + isFocusable = isSelectable + isClickable = isSelectable + setOnClickListener { view -> clickListener?.let { it(view) } } + } + button?.isEnabled = isEnabled + button?.icon = icon + } + + /** + * Set a listener for button click + */ + fun setOnClickListener(listener: (View) -> Unit) { + clickListener = listener + } +}
\ No newline at end of file diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt index 8e850465ef7d..be705b583974 100644 --- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt +++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt @@ -76,7 +76,7 @@ annotation class SensitivityLevel { } /** Preference interface that has a value persisted in datastore. */ -interface PersistentPreference<T> { +interface PersistentPreference<T> : PreferenceMetadata { /** * The value type the preference is associated with. @@ -93,7 +93,7 @@ interface PersistentPreference<T> { * [PreferenceScreenRegistry.getKeyValueStore]. */ fun storage(context: Context): KeyValueStore = - PreferenceScreenRegistry.getKeyValueStore(context, this as PreferenceMetadata)!! + PreferenceScreenRegistry.getKeyValueStore(context, this)!! /** Returns the required permissions to read preference value. */ fun getReadPermissions(context: Context): Permissions? = null @@ -111,7 +111,7 @@ interface PersistentPreference<T> { context, callingPid, callingUid, - this as PreferenceMetadata, + this, ) /** Returns the required permissions to write preference value. */ @@ -136,7 +136,7 @@ interface PersistentPreference<T> { value, callingPid, callingUid, - this as PreferenceMetadata, + this, ) /** The sensitivity level of the preference. */ diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceTypes.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceTypes.kt index 623ea22410e5..fecf3e50800a 100644 --- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceTypes.kt +++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceTypes.kt @@ -30,9 +30,6 @@ interface FloatValuePreference : PersistentPreference<Float> { get() = Float::class.javaObjectType } -/** Common base class for preferences that have two selectable states and save a boolean value. */ -interface TwoStatePreference : PreferenceMetadata, BooleanValuePreference - /** A preference that provides a two-state toggleable option. */ open class SwitchPreference @JvmOverloads @@ -40,9 +37,10 @@ constructor( override val key: String, @StringRes override val title: Int = 0, @StringRes override val summary: Int = 0, -) : TwoStatePreference +) : BooleanValuePreference /** A preference that provides a two-state toggleable option that can be used as a main switch. */ open class MainSwitchPreference @JvmOverloads -constructor(override val key: String, @StringRes override val title: Int = 0) : TwoStatePreference +constructor(override val key: String, @StringRes override val title: Int = 0) : + BooleanValuePreference diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt index b82c554ea26a..65fbe2b66e77 100644 --- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt +++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt @@ -66,7 +66,7 @@ interface PreferenceCategoryBinding : PreferenceBinding { } /** A boolean value type preference associated with the abstract [TwoStatePreference]. */ -interface TwoStatePreferenceBinding : PreferenceBinding { +interface BooleanValuePreferenceBinding : PreferenceBinding { override fun bind(preference: Preference, metadata: PreferenceMetadata) { super.bind(preference, metadata) @@ -78,7 +78,7 @@ interface TwoStatePreferenceBinding : PreferenceBinding { } /** A boolean value type preference associated with [SwitchPreferenceCompat]. */ -interface SwitchPreferenceBinding : TwoStatePreferenceBinding { +interface SwitchPreferenceBinding : BooleanValuePreferenceBinding { override fun createWidget(context: Context): Preference = SwitchPreferenceCompat(context) @@ -88,7 +88,7 @@ interface SwitchPreferenceBinding : TwoStatePreferenceBinding { } /** A boolean value type preference associated with [MainSwitchPreference]. */ -interface MainSwitchPreferenceBinding : TwoStatePreferenceBinding { +interface MainSwitchPreferenceBinding : BooleanValuePreferenceBinding { override fun createWidget(context: Context): Preference = MainSwitchPreference(context) diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp index 1661dfb2a86b..e5c009dcdded 100644 --- a/packages/SettingsLib/SettingsTheme/Android.bp +++ b/packages/SettingsLib/SettingsTheme/Android.bp @@ -16,6 +16,7 @@ android_library { ], resource_dirs: ["res"], static_libs: [ + "aconfig_settingstheme_exported_flags_java_lib", "androidx.preference_preference", "com.google.android.material_material", ], @@ -23,12 +24,12 @@ android_library { min_sdk_version: "21", apex_available: [ "//apex_available:platform", + "com.android.adservices", "com.android.cellbroadcast", "com.android.devicelock", "com.android.extservices", - "com.android.permission", - "com.android.adservices", "com.android.healthfitness", "com.android.mediaprovider", + "com.android.permission", ], } diff --git a/packages/SettingsLib/SettingsTheme/aconfig/settingstheme.aconfig b/packages/SettingsLib/SettingsTheme/aconfig/settingstheme.aconfig new file mode 100644 index 000000000000..83e732b63c15 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/aconfig/settingstheme.aconfig @@ -0,0 +1,10 @@ +package: "com.android.settingslib.widget.theme.flags" +container: "system" + +flag { + name: "is_expressive_design_enabled" + namespace: "android_settings" + description: "enable expressive design in Settings" + bug: "386013400" + is_exported: true +}
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_chevron.xml b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_chevron.xml index 94476538a6a5..94476538a6a5 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_chevron.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_chevron.xml diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_collapse.xml b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_collapse.xml index 161ece73f21c..161ece73f21c 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_collapse.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_collapse.xml diff --git a/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_cross.xml b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_cross.xml new file mode 100644 index 000000000000..3ba85a2a6c79 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_cross.xml @@ -0,0 +1,36 @@ +<!-- + Copyright (C) 2025 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. + --> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <shape + android:shape="oval"> + <size android:width="28dp" android:height="28dp"/> + <solid android:color="@color/settingslib_materialColorSurfaceContainerHigh"/> + </shape> + </item> + <item android:gravity="center"> + <vector + android:width="16dp" + android:height="16dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="@color/settingslib_materialColorOnSurface" + android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12 19,6.41z"/> + </vector> + </item> +</layer-list> diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_expand.xml b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_expand.xml index 1b5d5182d9b2..1b5d5182d9b2 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_expand.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_expand.xml diff --git a/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_level_high.xml b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_level_high.xml new file mode 100644 index 000000000000..aa4155bc939c --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_level_high.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <vector + android:width="20dp" + android:height="20dp" + android:viewportWidth="20" + android:viewportHeight="20"> + <path + android:pathData="M8.804,0.296C9.554,-0.099 10.446,-0.099 11.196,0.296L12.45,0.955C12.703,1.088 12.976,1.178 13.257,1.221L14.654,1.436C15.489,1.564 16.211,2.096 16.589,2.862L17.223,4.144C17.349,4.402 17.518,4.637 17.721,4.84L18.726,5.847C19.328,6.449 19.603,7.31 19.465,8.155L19.236,9.57C19.189,9.855 19.189,10.145 19.236,10.43L19.465,11.845C19.603,12.69 19.328,13.55 18.726,14.153L17.721,15.16C17.518,15.363 17.349,15.597 17.223,15.856L16.589,17.137C16.211,17.903 15.489,18.435 14.654,18.564L13.257,18.78C12.976,18.822 12.703,18.913 12.45,19.045L11.196,19.704C10.446,20.099 9.554,20.099 8.804,19.704L7.549,19.045C7.297,18.913 7.024,18.822 6.743,18.78L5.346,18.564C4.511,18.435 3.789,17.903 3.411,17.137L2.777,15.856C2.651,15.597 2.482,15.363 2.279,15.16L1.274,14.153C0.672,13.55 0.397,12.69 0.535,11.845L0.764,10.43C0.811,10.145 0.811,9.855 0.764,9.57L0.535,8.155C0.397,7.31 0.672,6.449 1.274,5.847L2.279,4.84C2.482,4.637 2.651,4.402 2.777,4.144L3.411,2.862C3.789,2.096 4.511,1.564 5.346,1.436L6.743,1.221C7.024,1.178 7.297,1.088 7.549,0.955L8.804,0.296Z" + android:fillColor="@color/settingslib_colorBackgroundLevel_high"/> + </vector> + </item> + <item android:gravity="center"> + <vector + android:width="4dp" + android:height="12dp" + android:viewportWidth="4" + android:viewportHeight="12"> + <path + android:pathData="M0.894,8.081V0.919H3.106V8.081H0.894ZM0.894,11.081V8.869H3.106V11.081H0.894Z" + android:fillColor="@color/settingslib_colorContentLevel_high"/> + </vector> + </item> +</layer-list>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_level_low.xml b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_level_low.xml new file mode 100644 index 000000000000..9caa09516de9 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_level_low.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <vector + android:width="20dp" + android:height="20dp" + android:viewportWidth="20" + android:viewportHeight="20"> + <path + android:pathData="M8.804,0.296C9.554,-0.099 10.446,-0.099 11.196,0.296L12.45,0.955C12.703,1.088 12.976,1.178 13.257,1.221L14.654,1.436C15.489,1.564 16.211,2.096 16.589,2.862L17.223,4.144C17.349,4.402 17.518,4.637 17.721,4.84L18.726,5.847C19.328,6.449 19.603,7.31 19.465,8.155L19.236,9.57C19.189,9.855 19.189,10.145 19.236,10.43L19.465,11.845C19.603,12.69 19.328,13.55 18.726,14.153L17.721,15.16C17.518,15.363 17.349,15.597 17.223,15.856L16.589,17.137C16.211,17.903 15.489,18.435 14.654,18.564L13.257,18.78C12.976,18.822 12.703,18.913 12.45,19.045L11.196,19.704C10.446,20.099 9.554,20.099 8.804,19.704L7.549,19.045C7.297,18.913 7.024,18.822 6.743,18.78L5.346,18.564C4.511,18.435 3.789,17.903 3.411,17.137L2.777,15.856C2.651,15.597 2.482,15.363 2.279,15.16L1.274,14.153C0.672,13.55 0.397,12.69 0.535,11.845L0.764,10.43C0.811,10.145 0.811,9.855 0.764,9.57L0.535,8.155C0.397,7.31 0.672,6.449 1.274,5.847L2.279,4.84C2.482,4.637 2.651,4.402 2.777,4.144L3.411,2.862C3.789,2.096 4.511,1.564 5.346,1.436L6.743,1.221C7.024,1.178 7.297,1.088 7.549,0.955L8.804,0.296Z" + android:fillColor="@color/settingslib_colorBackgroundLevel_low"/> + </vector> + </item> + <item android:gravity="center"> + <vector + android:width="10dp" + android:height="9dp" + android:viewportWidth="10" + android:viewportHeight="9"> + <path + android:pathData="M3.5,8.975L0.069,5.544L1.644,3.969L3.5,5.825L8.356,0.969L9.931,2.544L3.5,8.975Z" + android:fillColor="@color/settingslib_colorContentLevel_low"/> + </vector> + </item> +</layer-list>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_level_medium.xml b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_level_medium.xml new file mode 100644 index 000000000000..cdcb98246d56 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_level_medium.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <vector + android:width="20dp" + android:height="20dp" + android:viewportWidth="20" + android:viewportHeight="20"> + <path + android:pathData="M8.804,0.296C9.554,-0.099 10.446,-0.099 11.196,0.296L12.45,0.955C12.703,1.088 12.976,1.178 13.257,1.221L14.654,1.436C15.489,1.564 16.211,2.096 16.589,2.862L17.223,4.144C17.349,4.402 17.518,4.637 17.721,4.84L18.726,5.847C19.328,6.449 19.603,7.31 19.465,8.155L19.236,9.57C19.189,9.855 19.189,10.145 19.236,10.43L19.465,11.845C19.603,12.69 19.328,13.55 18.726,14.153L17.721,15.16C17.518,15.363 17.349,15.597 17.223,15.856L16.589,17.137C16.211,17.903 15.489,18.435 14.654,18.564L13.257,18.78C12.976,18.822 12.703,18.913 12.45,19.045L11.196,19.704C10.446,20.099 9.554,20.099 8.804,19.704L7.549,19.045C7.297,18.913 7.024,18.822 6.743,18.78L5.346,18.564C4.511,18.435 3.789,17.903 3.411,17.137L2.777,15.856C2.651,15.597 2.482,15.363 2.279,15.16L1.274,14.153C0.672,13.55 0.397,12.69 0.535,11.845L0.764,10.43C0.811,10.145 0.811,9.855 0.764,9.57L0.535,8.155C0.397,7.31 0.672,6.449 1.274,5.847L2.279,4.84C2.482,4.637 2.651,4.402 2.777,4.144L3.411,2.862C3.789,2.096 4.511,1.564 5.346,1.436L6.743,1.221C7.024,1.178 7.297,1.088 7.549,0.955L8.804,0.296Z" + android:fillColor="@color/settingslib_colorBackgroundLevel_medium"/> + </vector> + </item> + <item android:gravity="center"> + <vector + android:width="4dp" + android:height="12dp" + android:viewportWidth="4" + android:viewportHeight="12"> + <path + android:pathData="M0.894,8.081V0.919H3.106V8.081H0.894ZM0.894,11.081V8.869H3.106V11.081H0.894Z" + android:fillColor="@color/settingslib_colorContentLevel_medium"/> + </vector> + </item> +</layer-list>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_level_normal.xml b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_level_normal.xml new file mode 100644 index 000000000000..448d596f05ec --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_level_normal.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <vector + android:width="20dp" + android:height="20dp" + android:viewportWidth="20" + android:viewportHeight="20"> + <path + android:pathData="M8.804,0.296C9.554,-0.099 10.446,-0.099 11.196,0.296L12.45,0.955C12.703,1.088 12.976,1.178 13.257,1.221L14.654,1.436C15.489,1.564 16.211,2.096 16.589,2.862L17.223,4.144C17.349,4.402 17.518,4.637 17.721,4.84L18.726,5.847C19.328,6.449 19.603,7.31 19.465,8.155L19.236,9.57C19.189,9.855 19.189,10.145 19.236,10.43L19.465,11.845C19.603,12.69 19.328,13.55 18.726,14.153L17.721,15.16C17.518,15.363 17.349,15.597 17.223,15.856L16.589,17.137C16.211,17.903 15.489,18.435 14.654,18.564L13.257,18.78C12.976,18.822 12.703,18.913 12.45,19.045L11.196,19.704C10.446,20.099 9.554,20.099 8.804,19.704L7.549,19.045C7.297,18.913 7.024,18.822 6.743,18.78L5.346,18.564C4.511,18.435 3.789,17.903 3.411,17.137L2.777,15.856C2.651,15.597 2.482,15.363 2.279,15.16L1.274,14.153C0.672,13.55 0.397,12.69 0.535,11.845L0.764,10.43C0.811,10.145 0.811,9.855 0.764,9.57L0.535,8.155C0.397,7.31 0.672,6.449 1.274,5.847L2.279,4.84C2.482,4.637 2.651,4.402 2.777,4.144L3.411,2.862C3.789,2.096 4.511,1.564 5.346,1.436L6.743,1.221C7.024,1.178 7.297,1.088 7.549,0.955L8.804,0.296Z" + android:fillColor="@color/settingslib_materialColorOnSurface"/> + </vector> + </item> + <item android:gravity="center"> + <vector + android:width="14dp" + android:height="4dp" + android:viewportWidth="14" + android:viewportHeight="4"> + <path + android:pathData="M0.962,3.106V0.894H13.038V3.106H0.962Z" + android:fillColor="@color/settingslib_materialColorSurface"/> + </vector> + </item> +</layer-list>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_up.xml b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_up.xml new file mode 100644 index 000000000000..c38730534f03 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_up.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 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. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960"> + <path + android:fillColor="@color/settingslib_materialColorOnSurface" + android:pathData="M480,432L296,616L240,560L480,320L720,560L664,616L480,432Z"/> +</vector>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference.xml index 511e2bb64f1e..4ef747a99b49 100644 --- a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference.xml +++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference.xml @@ -19,7 +19,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" - android:minHeight="?android:attr/listPreferredItemHeightSmall" + android:minHeight="72dp" android:gravity="center_vertical" android:paddingStart="?android:attr/listPreferredItemPaddingStart" android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" diff --git a/packages/SettingsLib/SettingsTheme/res/values-night/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night/colors.xml index e57fe4f512fe..d677bbaa4ee8 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-night/colors.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-night/colors.xml @@ -50,4 +50,9 @@ <color name="settingslib_materialColorSurfaceContainerLow">#0E0E0E</color> <color name="settingslib_materialColorSurfaceContainerHigh">#2A2A2A</color> <color name="settingslib_materialColorSurfaceContainerHighest">#343434</color> + + <color name="settingslib_colorBackgroundLevel_high">@color/m3_ref_palette_red60</color> + <color name="settingslib_colorContentLevel_high">@color/m3_ref_palette_red10</color> + <color name="settingslib_colorBackgroundLevel_low">@color/m3_ref_palette_green70</color> + <color name="settingslib_colorContentLevel_low">@color/m3_ref_palette_green10</color> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/values/colors.xml b/packages/SettingsLib/SettingsTheme/res/values/colors.xml index c5c613b4b329..e8ab99e6bc14 100644 --- a/packages/SettingsLib/SettingsTheme/res/values/colors.xml +++ b/packages/SettingsLib/SettingsTheme/res/values/colors.xml @@ -76,4 +76,11 @@ <color name="settingslib_materialColorSurfaceContainerLowest">#FFFFFF</color> <color name="settingslib_materialColorSurfaceContainerHigh">#E8E8E8</color> <color name="settingslib_materialColorSurfaceContainerHighest">#E3E3E3</color> + + <color name="settingslib_colorBackgroundLevel_high">@color/m3_ref_palette_red50</color> + <color name="settingslib_colorContentLevel_high">@color/m3_ref_palette_red100</color> + <color name="settingslib_colorBackgroundLevel_medium">@color/m3_ref_palette_yellow80</color> + <color name="settingslib_colorContentLevel_medium">@color/m3_ref_palette_yellow10</color> + <color name="settingslib_colorBackgroundLevel_low">@color/m3_ref_palette_green50</color> + <color name="settingslib_colorContentLevel_low">@color/m3_ref_palette_green100</color> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt index 6794cd0e30a2..1776d252e28b 100644 --- a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt +++ b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt @@ -18,6 +18,7 @@ package com.android.settingslib.widget import android.content.Context import android.os.Build +import com.android.settingslib.widget.theme.flags.Flags object SettingsThemeHelper { private const val IS_EXPRESSIVE_DESIGN_ENABLED = "is_expressive_design_enabled" @@ -56,7 +57,8 @@ object SettingsThemeHelper { expressiveThemeState = if ( (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) && - getPropBoolean(context, IS_EXPRESSIVE_DESIGN_ENABLED, false) + (getPropBoolean(context, IS_EXPRESSIVE_DESIGN_ENABLED, false) || + Flags.isExpressiveDesignEnabled()) ) { ExpressiveThemeState.ENABLED } else { diff --git a/packages/SettingsLib/Spa/.gitignore b/packages/SettingsLib/Spa/.gitignore index b2ed2681b24c..5790fde1a797 100644 --- a/packages/SettingsLib/Spa/.gitignore +++ b/packages/SettingsLib/Spa/.gitignore @@ -7,6 +7,7 @@ /.idea/workspace.xml /.idea/navEditor.xml /.idea/assetWizardSettings.xml +/.kotlin .DS_Store build /captures diff --git a/packages/SettingsLib/Spa/build.gradle.kts b/packages/SettingsLib/Spa/build.gradle.kts index cf695d0543c7..5e72c43ef494 100644 --- a/packages/SettingsLib/Spa/build.gradle.kts +++ b/packages/SettingsLib/Spa/build.gradle.kts @@ -28,7 +28,7 @@ val androidTop: String = File(rootDir, "../../../../..").canonicalPath allprojects { extra["androidTop"] = androidTop - extra["jetpackComposeVersion"] = "1.8.0-alpha06" + extra["jetpackComposeVersion"] = "1.8.0-alpha08" } subprojects { diff --git a/packages/SettingsLib/Spa/gradle/libs.versions.toml b/packages/SettingsLib/Spa/gradle/libs.versions.toml index 04ef96a89843..4113ad86b5f8 100644 --- a/packages/SettingsLib/Spa/gradle/libs.versions.toml +++ b/packages/SettingsLib/Spa/gradle/libs.versions.toml @@ -15,9 +15,9 @@ # [versions] -agp = "8.7.3" +agp = "8.8.0" dexmaker-mockito = "2.28.3" -jvm = "17" +jvm = "21" kotlin = "2.0.21" truth = "1.4.4" diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts index a0bbb0ca9ae6..13966299b923 100644 --- a/packages/SettingsLib/Spa/spa/build.gradle.kts +++ b/packages/SettingsLib/Spa/spa/build.gradle.kts @@ -52,14 +52,14 @@ android { dependencies { api(project(":SettingsLibColor")) api("androidx.appcompat:appcompat:1.7.0") - api("androidx.compose.material3:material3:1.4.0-alpha04") + api("androidx.compose.material3:material3:1.4.0-alpha05") api("androidx.compose.material:material-icons-extended") api("androidx.compose.runtime:runtime-livedata:$jetpackComposeVersion") api("androidx.compose.ui:ui-tooling-preview:$jetpackComposeVersion") api("androidx.graphics:graphics-shapes-android:1.0.1") api("androidx.lifecycle:lifecycle-livedata-ktx") api("androidx.lifecycle:lifecycle-runtime-compose") - api("androidx.navigation:navigation-compose:2.9.0-alpha03") + api("androidx.navigation:navigation-compose:2.9.0-alpha04") api("com.github.PhilJay:MPAndroidChart:v3.1.0-alpha") api("com.google.android.material:material:1.13.0-alpha08") debugApi("androidx.compose.ui:ui-tooling:$jetpackComposeVersion") diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/DropdownTextBox.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/DropdownTextBox.kt index bdbe62c07425..8e59fd74c740 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/DropdownTextBox.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/DropdownTextBox.kt @@ -20,9 +20,9 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExposedDropdownMenuAnchorType import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuDefaults -import androidx.compose.material3.MenuAnchorType import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -66,7 +66,7 @@ internal fun DropdownTextBox( OutlinedTextField( // The `menuAnchor` modifier must be passed to the text field for correctness. modifier = Modifier - .menuAnchor(MenuAnchorType.PrimaryNotEditable) + .menuAnchor(ExposedDropdownMenuAnchorType.PrimaryNotEditable) .fillMaxWidth(), value = text, onValueChange = { }, diff --git a/packages/SettingsLib/Spa/testutils/build.gradle.kts b/packages/SettingsLib/Spa/testutils/build.gradle.kts index 7dbd320c7d5a..03cd243932bd 100644 --- a/packages/SettingsLib/Spa/testutils/build.gradle.kts +++ b/packages/SettingsLib/Spa/testutils/build.gradle.kts @@ -36,7 +36,7 @@ android { dependencies { api(project(":spa")) - api("androidx.arch.core:core-testing:2.2.0-alpha01") + api("androidx.arch.core:core-testing:2.2.0") api("androidx.compose.ui:ui-test-junit4:$jetpackComposeVersion") api("androidx.lifecycle:lifecycle-runtime-testing") api("org.mockito.kotlin:mockito-kotlin:2.2.11") diff --git a/packages/SettingsLib/res/values/config.xml b/packages/SettingsLib/res/values/config.xml index 3c3de044cc4e..502eb6c7296a 100644 --- a/packages/SettingsLib/res/values/config.xml +++ b/packages/SettingsLib/res/values/config.xml @@ -41,4 +41,15 @@ <string name="config_avatar_picker_class" translatable="false"> com.android.avatarpicker.ui.AvatarPickerActivity </string> + + <array name="config_override_carrier_5g_plus"> + <item>@array/carrier_2032_5g_plus</item> + </array> + + <integer-array name="carrier_2032_5g_plus"> + <!-- carrier id: 2032 --> + <item>2032</item> + <!-- network type: "5G+" --> + <item>@string/data_connection_5g_plus_carrier_2032</item> + </integer-array> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 6cf9e83ef342..3da2271431f8 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1723,6 +1723,8 @@ <!-- Content description of the data connection type 5G+. [CHAR LIMIT=NONE] --> <string name="data_connection_5g_plus" translatable="false">5G+</string> + <!-- Content description of the data connection type 5G+ for carrier 2032. [CHAR LIMIT=NONE] --> + <string name="data_connection_5g_plus_carrier_2032" translatable="false">5G+</string> <!-- Content description of the data connection type Carrier WiFi. [CHAR LIMIT=NONE] --> <string name="data_connection_carrier_wifi">W+</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileMappings.java b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileMappings.java index b7108c98c3fe..cf52eb3ab060 100644 --- a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileMappings.java +++ b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileMappings.java @@ -15,11 +15,14 @@ */ package com.android.settingslib.mobile; +import android.annotation.SuppressLint; import android.content.Context; import android.content.res.Resources; +import android.content.res.TypedArray; import android.os.PersistableBundle; import android.telephony.Annotation; import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; @@ -196,9 +199,9 @@ public class MobileMappings { networkToIconLookup.put(toDisplayIconKey( TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA), TelephonyIcons.NR_5G); - networkToIconLookup.put(toDisplayIconKey( - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED), - TelephonyIcons.NR_5G_PLUS); + networkToIconLookup.put( + toDisplayIconKey(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED), + config.mobileIconGroup5gPlus); networkToIconLookup.put(toIconKey( TelephonyManager.NETWORK_TYPE_NR), TelephonyIcons.NR_5G); @@ -217,6 +220,7 @@ public class MobileMappings { public boolean hideLtePlus = false; public boolean hspaDataDistinguishable; public boolean alwaysShowDataRatIcon = false; + public MobileIconGroup mobileIconGroup5gPlus = TelephonyIcons.NR_5G_PLUS; /** * Reads the latest configs. @@ -250,9 +254,54 @@ public class MobileMappings { config.hideLtePlus = b.getBoolean( CarrierConfigManager.KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL); } + + SubscriptionManager subscriptionManager = + context.getSystemService(SubscriptionManager.class); + if (subscriptionManager != null) { + SubscriptionInfo subInfo = subscriptionManager.getDefaultDataSubscriptionInfo(); + if (subInfo != null) { + readMobileIconGroup5gPlus(subInfo.getCarrierId(), res, config); + } + } return config; } + @SuppressLint("ResourceType") + private static void readMobileIconGroup5gPlus(int carrierId, Resources res, Config config) { + int networkTypeResId = 0; + TypedArray groupArray; + try { + groupArray = res.obtainTypedArray(R.array.config_override_carrier_5g_plus); + } catch (Resources.NotFoundException e) { + return; + } + for (int i = 0; i < groupArray.length() && networkTypeResId == 0; i++) { + int groupId = groupArray.getResourceId(i, 0); + if (groupId == 0) { + continue; + } + TypedArray carrierArray; + try { + carrierArray = res.obtainTypedArray(groupId); + } catch (Resources.NotFoundException e) { + continue; + } + int groupCarrierId = carrierArray.getInt(0, 0); + if (groupCarrierId == carrierId) { + networkTypeResId = carrierArray.getResourceId(1, 0); + } + carrierArray.recycle(); + } + groupArray.recycle(); + + if (networkTypeResId != 0) { + config.mobileIconGroup5gPlus = new MobileIconGroup( + TelephonyIcons.NR_5G_PLUS.name, + networkTypeResId, + TelephonyIcons.NR_5G_PLUS.dataType); + } + } + /** * Returns true if this config and the other config are semantically equal. * diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 7b4a2ca5de39..d367748d7dbf 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -92,6 +92,7 @@ public class SecureSettings { Settings.Secure.KEY_REPEAT_DELAY_MS, Settings.Secure.CAMERA_GESTURE_DISABLED, Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE, + Settings.Secure.ACCESSIBILITY_AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT, Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED, Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY, Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON, diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index 6681c014f2e0..242bdce0d79e 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -142,6 +142,8 @@ public class SecureSettingsValidators { VALIDATORS.put(Secure.CAMERA_GESTURE_DISABLED, BOOLEAN_VALIDATOR); VALIDATORS.put( Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE, NON_NEGATIVE_INTEGER_VALIDATOR); + VALIDATORS.put( + Secure.ACCESSIBILITY_AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.ACCESSIBILITY_AUTOCLICK_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.ACCESSIBILITY_AUTOCLICK_DELAY, NON_NEGATIVE_INTEGER_VALIDATOR); VALIDATORS.put(Secure.ACCESSIBILITY_LARGE_POINTER_ICON, BOOLEAN_VALIDATOR); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 1c6d6816e9b4..95059779ce3d 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -1718,6 +1718,9 @@ class SettingsProtoDumpUtil { Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE, SecureSettingsProto.Accessibility.AUTOCLICK_CURSOR_AREA_SIZE); dumpSetting(s, p, + Settings.Secure.ACCESSIBILITY_AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT, + SecureSettingsProto.Accessibility.AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT); + dumpSetting(s, p, Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED, SecureSettingsProto.Accessibility.AUTOCLICK_ENABLED); dumpSetting(s, p, diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index 9531bc38e797..1a7ae724ec59 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -176,13 +176,6 @@ flag { } flag { - name: "notifications_dismiss_pruned_summaries" - namespace: "systemui" - description: "NotifCollection.dismissNotifications will now dismiss summaries that are pruned from the shade." - bug: "355967751" -} - -flag { name: "notification_transparent_header_fix" namespace: "systemui" description: "fix the transparent group header issue for async header inflation." @@ -1940,3 +1933,10 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "ui_rich_ongoing_force_expanded" + namespace: "systemui" + description: "Force promoted notifications to always be expanded" + bug: "380901479" +} diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt index a1117e1bc1db..431a376d8eaf 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt @@ -159,6 +159,9 @@ interface BaseContentScope : ElementStateScope { /** The state of the [SceneTransitionLayout] in which this content is contained. */ val layoutState: SceneTransitionLayoutState + /** The [LookaheadScope] used by the [SceneTransitionLayout]. */ + val lookaheadScope: LookaheadScope + /** * Tag an element identified by [key]. * diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt index 59b4a09385f5..c61bb6ea1958 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt @@ -27,6 +27,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.LookaheadScope import androidx.compose.ui.layout.approachLayout import androidx.compose.ui.platform.testTag import androidx.compose.ui.unit.IntSize @@ -119,6 +120,9 @@ internal class ContentScopeImpl( override val layoutState: SceneTransitionLayoutState = layoutImpl.state + override val lookaheadScope: LookaheadScope + get() = layoutImpl.lookaheadScope + private val _verticalOverscrollEffect = OffsetOverscrollEffect( orientation = Orientation.Vertical, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt index 73efea764e59..2713bb0f3e23 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt @@ -316,5 +316,7 @@ class FontScalingDialogDelegateTest : SysuiTestCase() { dialog.onConfigurationChanged(config) testableLooper.processAllMessages() assertThat(doneButton.isEnabled).isTrue() + + dialog.dismiss() } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java index 4ef9792a2ad9..0df1073ca553 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java @@ -1383,7 +1383,6 @@ public class NotifCollectionTest extends SysuiTestCase { } @Test - @EnableFlags(Flags.FLAG_NOTIFICATIONS_DISMISS_PRUNED_SUMMARIES) public void testDismissNotificationsIncludesPrunedParents() { // GIVEN a collection with 2 groups; one has a single child, one has two. mCollection.addNotificationDismissInterceptor(mInterceptor1); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/TestableBubbleController.java index aa71b84d7bbc..75c174229564 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/TestableBubbleController.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/TestableBubbleController.java @@ -43,6 +43,7 @@ import com.android.wm.shell.onehanded.OneHandedController; import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; +import com.android.wm.shell.taskview.TaskViewRepository; import com.android.wm.shell.taskview.TaskViewTransitions; import com.android.wm.shell.transition.Transitions; @@ -76,6 +77,7 @@ public class TestableBubbleController extends BubbleController { DragAndDropController dragAndDropController, ShellExecutor shellMainExecutor, Handler shellMainHandler, + TaskViewRepository taskViewRepository, TaskViewTransitions taskViewTransitions, Transitions transitions, SyncTransactionQueue syncQueue, @@ -86,7 +88,7 @@ public class TestableBubbleController extends BubbleController { displayInsetsController, displayImeController, userManager, launcherApps, bubbleLogger, taskStackListener, shellTaskOrganizer, positioner, displayController, oneHandedOptional, dragAndDropController, shellMainExecutor, shellMainHandler, - new SyncExecutor(), taskViewTransitions, transitions, + new SyncExecutor(), taskViewRepository, taskViewTransitions, transitions, syncQueue, wmService, bubbleProperties); setInflateSynchronously(true); onInit(); diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt index 2ed0671a570b..3911c196e967 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt @@ -30,6 +30,8 @@ import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.statusbar.notification.collection.SortBySectionTimeFlag import com.android.systemui.statusbar.notification.emptyshade.shared.ModesEmptyShadeFix import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor +import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi +import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiForceExpanded import com.android.systemui.statusbar.notification.shared.NotificationAvalancheSuppression import com.android.systemui.statusbar.notification.shared.NotificationMinimalism import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun @@ -52,6 +54,7 @@ class FlagDependencies @Inject constructor(featureFlags: FeatureFlagsClassic, ha NotificationMinimalism.token dependsOn NotificationThrottleHun.token ModesEmptyShadeFix.token dependsOn modesUi + PromotedNotificationUiForceExpanded.token dependsOn PromotedNotificationUi.token // SceneContainer dependencies SceneContainerFlag.getFlagDependencies().forEach { (alpha, beta) -> alpha dependsOn beta } diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeStateTraceLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeStateTraceLogger.kt index 2705cdafb4de..39703ab5602c 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeStateTraceLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeStateTraceLogger.kt @@ -25,6 +25,8 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.shade.data.repository.ShadeDisplaysRepository import com.android.systemui.shade.domain.interactor.ShadeInteractor +import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround +import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -34,7 +36,7 @@ class ShadeStateTraceLogger @Inject constructor( private val shadeInteractor: ShadeInteractor, - private val shadeDisplaysRepository: ShadeDisplaysRepository, + private val shadeDisplaysRepository: Lazy<ShadeDisplaysRepository>, @Application private val scope: CoroutineScope, ) : CoreStartable { override fun start() { @@ -52,9 +54,11 @@ constructor( instantForGroup(TRACK_GROUP_NAME, "shadeExpansion", it) } } - launch { - shadeDisplaysRepository.displayId.collect { - instantForGroup(TRACK_GROUP_NAME, "displayId", it) + if (ShadeWindowGoesAround.isEnabled) { + launch { + shadeDisplaysRepository.get().displayId.collect { + instantForGroup(TRACK_GROUP_NAME, "displayId", it) + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java index cf9ee619b734..826329d5da1e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java @@ -39,7 +39,6 @@ import static android.service.notification.NotificationListenerService.REASON_TI import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED; import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED; -import static com.android.systemui.Flags.notificationsDismissPrunedSummaries; import static com.android.systemui.statusbar.notification.NotificationUtils.logKey; import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.DISMISSED; import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.NOT_DISMISSED; @@ -278,9 +277,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { Assert.isMainThread(); checkForReentrantCall(); - if (notificationsDismissPrunedSummaries()) { - entriesToDismiss = includeSummariesToDismiss(entriesToDismiss); - } + entriesToDismiss = includeSummariesToDismiss(entriesToDismiss); final int entryCount = entriesToDismiss.size(); final List<NotificationEntry> entriesToLocallyDismiss = new ArrayList<>(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiForceExpanded.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiForceExpanded.kt new file mode 100644 index 000000000000..cb0d67403521 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiForceExpanded.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2024 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.promoted + +import com.android.systemui.Flags +import com.android.systemui.flags.FlagToken +import com.android.systemui.flags.RefactorFlagUtils + +/** Helper for reading or using the expanded ui rich ongoing flag state. */ +@Suppress("NOTHING_TO_INLINE") +object PromotedNotificationUiForceExpanded { + /** The aconfig flag name */ + const val FLAG_NAME = Flags.FLAG_UI_RICH_ONGOING_FORCE_EXPANDED + + /** A token used for dependency declaration */ + val token: FlagToken + get() = FlagToken(FLAG_NAME, isEnabled) + + /** Is the refactor enabled */ + @JvmStatic + inline val isEnabled + get() = Flags.uiRichOngoingForceExpanded() + + /** + * Called to ensure code is only run when the flag is enabled. This protects users from the + * unintended behaviors caused by accidentally running new logic, while also crashing on an eng + * build to ensure that the refactor author catches issues in testing. + */ + @JvmStatic + inline fun isUnexpectedlyInLegacyMode() = + RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME) + + /** + * Called to ensure code is only run when the flag is enabled. This will throw an exception if + * the flag is not enabled to ensure that the refactor author catches issues in testing. + * Caution!! Using this check incorrectly will cause crashes in nextfood builds! + */ + @JvmStatic + inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME) + + /** + * Called to ensure code is only run when the flag is disabled. This will throw an exception if + * the flag is enabled to ensure that the refactor author catches issues in testing. + */ + @JvmStatic + inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME) +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index 7508838810ad..fab7922f58e7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -358,6 +358,8 @@ public class BubblesTest extends SysuiTestCase { private Display mDefaultDisplay; @Mock private Lazy<ViewCapture> mLazyViewCapture; + @Mock + private SyncTransactionQueue mSyncQueue; private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this); private ShadeInteractor mShadeInteractor; @@ -400,8 +402,6 @@ public class BubblesTest extends SysuiTestCase { if (Transitions.ENABLE_SHELL_TRANSITIONS) { doReturn(true).when(mTransitions).isRegistered(); } - mTaskViewRepository = new TaskViewRepository(); - mTaskViewTransitions = new TaskViewTransitions(mTransitions, mTaskViewRepository); mTestableLooper = TestableLooper.get(this); @@ -518,6 +518,9 @@ public class BubblesTest extends SysuiTestCase { Optional.empty(), Optional.empty(), syncExecutor); + mTaskViewRepository = new TaskViewRepository(); + mTaskViewTransitions = new TaskViewTransitions(mTransitions, mTaskViewRepository, + mShellTaskOrganizer, mSyncQueue); mBubbleProperties = new FakeBubbleProperties(); mBubbleController = new TestableBubbleController( mContext, @@ -542,6 +545,7 @@ public class BubblesTest extends SysuiTestCase { mock(DragAndDropController.class), syncExecutor, mock(Handler.class), + mTaskViewRepository, mTaskViewTransitions, mTransitions, mock(SyncTransactionQueue.class), diff --git a/ravenwood/texts/ravenwood-standard-options.txt b/ravenwood/texts/ravenwood-standard-options.txt index 3ec3e3ce2946..27223d8b72ff 100644 --- a/ravenwood/texts/ravenwood-standard-options.txt +++ b/ravenwood/texts/ravenwood-standard-options.txt @@ -5,6 +5,8 @@ # Keep all classes / methods / fields, but make the methods throw. --default-throw +--delete-finals + # Uncomment below lines to enable each feature. #--default-method-call-hook diff --git a/ravenwood/tools/hoststubgen/hoststubgen-standard-options.txt b/ravenwood/tools/hoststubgen/hoststubgen-standard-options.txt index 001943c18d6b..9c46a1646560 100644 --- a/ravenwood/tools/hoststubgen/hoststubgen-standard-options.txt +++ b/ravenwood/tools/hoststubgen/hoststubgen-standard-options.txt @@ -2,6 +2,8 @@ --debug +--delete-finals + # Uncomment below lines to enable each feature. #--default-method-call-hook diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt index cc704b2b32ed..985947575a86 100644 --- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt +++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt @@ -411,6 +411,8 @@ class HostStubGen(val options: HostStubGenOptions) { stats = stats, enablePreTrace = options.enablePreTrace.get, enablePostTrace = options.enablePostTrace.get, + deleteClassFinals = options.deleteFinals.get, + deleteMethodFinals = options.deleteFinals.get, ) outVisitor = BaseAdapter.getVisitor( classInternalName, classes, outVisitor, filter, diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt index 55e853e3e2fb..ae9276f711e1 100644 --- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt +++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt @@ -106,6 +106,8 @@ class HostStubGenOptions( var cleanUpOnError: SetOnce<Boolean> = SetOnce(false), + var deleteFinals: SetOnce<Boolean> = SetOnce(false), + var enableClassChecker: SetOnce<Boolean> = SetOnce(false), var enablePreTrace: SetOnce<Boolean> = SetOnce(false), var enablePostTrace: SetOnce<Boolean> = SetOnce(false), @@ -218,6 +220,8 @@ class HostStubGenOptions( "--gen-keep-all-file" -> ret.inputJarAsKeepAllFile.set(nextArg()) + "--delete-finals" -> ret.deleteFinals.set(true) + // Following options are for debugging. "--enable-class-checker" -> ret.enableClassChecker.set(true) "--no-class-checker" -> ret.enableClassChecker.set(false) @@ -293,6 +297,7 @@ class HostStubGenOptions( defaultMethodCallHook=$defaultMethodCallHook, policyOverrideFiles=${policyOverrideFiles.toTypedArray().contentToString()}, defaultPolicy=$defaultPolicy, + deleteFinals=$deleteFinals, cleanUpOnError=$cleanUpOnError, enableClassChecker=$enableClassChecker, enablePreTrace=$enablePreTrace, diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt index 261ef59c45c7..a08d1d605949 100644 --- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt +++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt @@ -50,7 +50,13 @@ abstract class BaseAdapter( val errors: HostStubGenErrors, val stats: HostStubGenStats?, val enablePreTrace: Boolean, - val enablePostTrace: Boolean + val enablePostTrace: Boolean, + val deleteClassFinals: Boolean, + val deleteMethodFinals: Boolean, + // We don't remove finals from fields, because final fields have a stronger memory + // guarantee than non-final fields, see: + // https://docs.oracle.com/javase/specs/jls/se22/html/jls-17.html#jls-17.5 + // i.e. changing a final field to non-final _could_ result in different behavior. ) protected lateinit var currentPackageName: String @@ -58,14 +64,33 @@ abstract class BaseAdapter( protected var redirectionClass: String? = null protected lateinit var classPolicy: FilterPolicyWithReason + private fun isEnum(access: Int): Boolean { + return (access and Opcodes.ACC_ENUM) != 0 + } + + protected fun modifyClassAccess(access: Int): Int { + if (options.deleteClassFinals && !isEnum(access)) { + return access and Opcodes.ACC_FINAL.inv() + } + return access + } + + protected fun modifyMethodAccess(access: Int): Int { + if (options.deleteMethodFinals) { + return access and Opcodes.ACC_FINAL.inv() + } + return access + } + override fun visit( version: Int, - access: Int, + origAccess: Int, name: String, signature: String?, superName: String?, interfaces: Array<String>, ) { + val access = modifyClassAccess(origAccess) super.visit(version, access, name, signature, superName, interfaces) currentClassName = name currentPackageName = getPackageNameFromFullClassName(name) @@ -130,13 +155,14 @@ abstract class BaseAdapter( } } - override fun visitMethod( - access: Int, + final override fun visitMethod( + origAccess: Int, name: String, descriptor: String, signature: String?, exceptions: Array<String>?, ): MethodVisitor? { + val access = modifyMethodAccess(origAccess) if (skipMemberModificationNestCount > 0) { return super.visitMethod(access, name, descriptor, signature, exceptions) } @@ -176,6 +202,7 @@ abstract class BaseAdapter( if (newAccess == NOT_COMPATIBLE) { return null } + newAccess = modifyMethodAccess(newAccess) log.v( "Emitting %s.%s%s as %s %s", currentClassName, name, descriptor, diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt index 567a69e43b58..70e7d46bb6cd 100644 --- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt +++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt @@ -51,12 +51,13 @@ class ImplGeneratingAdapter( override fun visit( version: Int, - access: Int, + origAccess: Int, name: String, signature: String?, superName: String?, interfaces: Array<String> ) { + val access = modifyClassAccess(origAccess) super.visit(version, access, name, signature, superName, interfaces) classLoadHooks = filter.getClassLoadHooks(currentClassName) diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/01-hoststubgen-test-tiny-framework-orig-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/01-hoststubgen-test-tiny-framework-orig-dump.txt index 5e5ca62b49f0..b009b0957919 100644 --- a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/01-hoststubgen-test-tiny-framework-orig-dump.txt +++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/01-hoststubgen-test-tiny-framework-orig-dump.txt @@ -7,6 +7,8 @@ public interface android.hosttest.annotation.HostSideTestClassLoadHook extends j this_class: #x // android/hosttest/annotation/HostSideTestClassLoadHook super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ public abstract java.lang.String value(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT @@ -30,6 +32,8 @@ public interface android.hosttest.annotation.HostSideTestIgnore extends java.lan this_class: #x // android/hosttest/annotation/HostSideTestIgnore super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestIgnore.java" RuntimeVisibleAnnotations: @@ -50,6 +54,8 @@ public interface android.hosttest.annotation.HostSideTestKeep extends java.lang. this_class: #x // android/hosttest/annotation/HostSideTestKeep super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestKeep.java" RuntimeVisibleAnnotations: @@ -70,6 +76,8 @@ public interface android.hosttest.annotation.HostSideTestRedirect extends java.l this_class: #x // android/hosttest/annotation/HostSideTestRedirect super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestRedirect.java" RuntimeVisibleAnnotations: @@ -90,6 +98,8 @@ public interface android.hosttest.annotation.HostSideTestRedirectionClass extend this_class: #x // android/hosttest/annotation/HostSideTestRedirectionClass super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ public abstract java.lang.String value(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT @@ -113,6 +123,8 @@ public interface android.hosttest.annotation.HostSideTestRemove extends java.lan this_class: #x // android/hosttest/annotation/HostSideTestRemove super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestRemove.java" RuntimeVisibleAnnotations: @@ -133,6 +145,8 @@ public interface android.hosttest.annotation.HostSideTestStaticInitializerKeep e this_class: #x // android/hosttest/annotation/HostSideTestStaticInitializerKeep super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestStaticInitializerKeep.java" RuntimeVisibleAnnotations: @@ -153,6 +167,8 @@ public interface android.hosttest.annotation.HostSideTestSubstitute extends java this_class: #x // android/hosttest/annotation/HostSideTestSubstitute super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ public abstract java.lang.String suffix(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT @@ -176,6 +192,8 @@ public interface android.hosttest.annotation.HostSideTestThrow extends java.lang this_class: #x // android/hosttest/annotation/HostSideTestThrow super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestThrow.java" RuntimeVisibleAnnotations: @@ -196,6 +214,8 @@ public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends this_class: #x // android/hosttest/annotation/HostSideTestWholeClassKeep super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestWholeClassKeep.java" RuntimeVisibleAnnotations: @@ -216,6 +236,8 @@ public interface android.hosttest.annotation.tests.HostSideTestSuppress extends this_class: #x // android/hosttest/annotation/tests/HostSideTestSuppress super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestSuppress.java" RuntimeVisibleAnnotations: @@ -232,6 +254,8 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Pro this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 3 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -273,6 +297,8 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 3 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -314,6 +340,8 @@ public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 0, attributes: 3 +Constant pool: +{ } SourceFile: "IPretendingAidl.java" NestMembers: @@ -331,6 +359,8 @@ public class com.android.hoststubgen.test.tinyframework.R$Nested this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 2, attributes: 3 +Constant pool: +{ public static int[] ARRAY; descriptor: [I flags: (0x0009) ACC_PUBLIC, ACC_STATIC @@ -376,6 +406,8 @@ public class com.android.hoststubgen.test.tinyframework.R this_class: #x // com/android/hoststubgen/test/tinyframework/R super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 3 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.R(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -396,13 +428,15 @@ InnerClasses: public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.class Compiled from "TinyFrameworkAnnotations.java" -public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations +public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations minor version: 0 major version: 65 - flags: (0x0021) ACC_PUBLIC, ACC_SUPER + flags: (0x0031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 9, attributes: 2 +Constant pool: +{ public int keep; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -433,9 +467,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations x: #x() android.hosttest.annotation.HostSideTestKeep - public int addOne(int); + public final int addOne(int); descriptor: (I)I - flags: (0x0001) ACC_PUBLIC + flags: (0x0011) ACC_PUBLIC, ACC_FINAL Code: stack=2, locals=2, args_size=2 x: iload_1 @@ -505,18 +539,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations; 0 4 1 value I - public static native int nativeAddThree(int); + public static final native int nativeAddThree(int); descriptor: (I)I - flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE + flags: (0x0119) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_NATIVE RuntimeInvisibleAnnotations: x: #x(#x=s#x) android.hosttest.annotation.HostSideTestSubstitute( suffix="_host" ) - private static int nativeAddThree_host(int); + private static final int nativeAddThree_host(int); descriptor: (I)I - flags: (0x000a) ACC_PRIVATE, ACC_STATIC + flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL Code: stack=2, locals=1, args_size=1 x: iload_0 @@ -578,6 +612,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 3, attributes: 2 +Constant pool: +{ public static final java.util.Set<java.lang.Class<?>> sLoadedClasses; descriptor: Ljava/util/Set; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL @@ -640,6 +676,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAn this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 6, attributes: 2 +Constant pool: +{ public int keep; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -764,6 +802,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 2, attributes: 2 +Constant pool: +{ public static boolean sInitialized; descriptor: Z flags: (0x0009) ACC_PUBLIC, ACC_STATIC @@ -818,6 +858,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 2, attributes: 2 +Constant pool: +{ public static boolean sInitialized; descriptor: Z flags: (0x0009) ACC_PUBLIC, ACC_STATIC @@ -878,6 +920,8 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex super_class: #x // java/lang/Enum interfaces: 0, fields: 6, methods: 7, attributes: 3 +Constant pool: +{ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM @@ -1081,6 +1125,8 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple super_class: #x // java/lang/Enum interfaces: 0, fields: 3, methods: 5, attributes: 3 +Constant pool: +{ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM @@ -1202,6 +1248,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTe this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 2 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -1256,6 +1304,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 17, attributes: 1 +Constant pool: +{ public int stub; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -1507,6 +1557,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 8, attributes: 5 +Constant pool: +{ public final java.util.function.Supplier<java.lang.Integer> mSupplier; descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL @@ -1661,6 +1713,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 8, attributes: 5 +Constant pool: +{ public final java.util.function.Supplier<java.lang.Integer> mSupplier; descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL @@ -1816,6 +1870,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 3, attributes: 3 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -1873,6 +1929,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 5, attributes: 5 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -1984,6 +2042,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 14, attributes: 2 +Constant pool: +{ int value; descriptor: I flags: (0x0000) @@ -2157,6 +2217,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 7, attributes: 2 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -2263,6 +2325,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 ex this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 3, attributes: 5 +Constant pool: +{ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses); descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V flags: (0x0000) @@ -2321,6 +2385,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 ex this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 3, attributes: 5 +Constant pool: +{ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2(); descriptor: ()V flags: (0x0000) @@ -2375,6 +2441,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 ex this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 3, attributes: 5 +Constant pool: +{ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses); descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V flags: (0x0000) @@ -2433,6 +2501,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 ex this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 3, attributes: 5 +Constant pool: +{ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4(); descriptor: ()V flags: (0x0000) @@ -2487,6 +2557,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 1, attributes: 3 +Constant pool: +{ public int value; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -2521,6 +2593,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 1, attributes: 3 +Constant pool: +{ public int value; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -2558,6 +2632,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$Stat this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 3, attributes: 5 +Constant pool: +{ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1(); descriptor: ()V flags: (0x0000) @@ -2613,6 +2689,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 1, attributes: 3 +Constant pool: +{ public int value; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -2647,6 +2725,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 2, attributes: 3 +Constant pool: +{ public int value; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -2694,6 +2774,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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: 3 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass(int); descriptor: (I)V flags: (0x0001) ACC_PUBLIC @@ -2723,6 +2805,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 4, attributes: 4 +Constant pool: +{ public final java.util.function.Supplier<java.lang.Integer> mSupplier; descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL @@ -2827,6 +2911,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedi this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 2 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -2869,6 +2955,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClas this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 2 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -2911,6 +2999,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 2, attributes: 2 +Constant pool: +{ private final int mValue; descriptor: I flags: (0x0012) ACC_PRIVATE, ACC_FINAL @@ -2958,6 +3048,8 @@ public class com.android.hoststubgen.test.tinyframework.packagetest.A this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/A super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.packagetest.A(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -2981,6 +3073,8 @@ public class com.android.hoststubgen.test.tinyframework.packagetest.B this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/B super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.packagetest.B(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3004,6 +3098,8 @@ public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/A super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.packagetest.sub.A(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3027,6 +3123,8 @@ public class com.android.hoststubgen.test.tinyframework.packagetest.sub.B this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/B super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.packagetest.sub.B(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3050,6 +3148,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.C1 this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1 super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.C1(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3073,6 +3173,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.C2 extends this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2 super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1 interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.C2(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3096,6 +3198,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.C3 extends this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C3 super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2 interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.C3(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3119,6 +3223,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.CA this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CA super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.CA(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3142,6 +3248,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.CB this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CB super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.CB(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3165,6 +3273,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C1 ex this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1 super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1 interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_C1(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3188,6 +3298,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C2 ex this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2 super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2 interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_C2(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3211,6 +3323,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C3 ex this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3 super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C3 interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_C3(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3234,6 +3348,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_CA ex this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_CA super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CA interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_CA(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3257,6 +3373,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_CB ex this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CB interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_CB(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3280,6 +3398,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_CB_IA this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB_IA super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CB interfaces: 1, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_CB_IA(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3303,6 +3423,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1 im this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3326,6 +3448,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1_IA this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA super_class: #x // java/lang/Object interfaces: 2, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1_IA(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3349,6 +3473,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I2 im this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I2(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3372,6 +3498,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3 im this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3395,6 +3523,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3_IA this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3_IA super_class: #x // java/lang/Object interfaces: 2, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3_IA(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3418,6 +3548,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA im this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3441,6 +3573,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA_I1 this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I1 super_class: #x // java/lang/Object interfaces: 2, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA_I1(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3464,6 +3598,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA_I3 this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I3 super_class: #x // java/lang/Object interfaces: 2, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA_I3(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3487,6 +3623,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IB im this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IB(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3510,6 +3648,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IB_IA this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB_IA super_class: #x // java/lang/Object interfaces: 2, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IB_IA(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3533,6 +3673,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_None this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_None super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_None(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3556,6 +3698,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.I1 this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I1 super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 0, attributes: 1 +Constant pool: +{ } SourceFile: "I1.java" ## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I2.class @@ -3567,6 +3711,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.I2 exte this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I2 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 1 +Constant pool: +{ } SourceFile: "I2.java" ## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I3.class @@ -3578,6 +3724,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.I3 exte this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I3 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 1 +Constant pool: +{ } SourceFile: "I3.java" ## Class: com/android/hoststubgen/test/tinyframework/subclasstest/IA.class @@ -3589,6 +3737,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.IA this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/IA super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 0, attributes: 1 +Constant pool: +{ } SourceFile: "IA.java" ## Class: com/android/hoststubgen/test/tinyframework/subclasstest/IB.class @@ -3600,6 +3750,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.IB this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/IB super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 0, attributes: 1 +Constant pool: +{ } SourceFile: "IB.java" ## Class: com/supported/UnsupportedClass.class @@ -3611,6 +3763,8 @@ public class com.supported.UnsupportedClass this_class: #x // com/supported/UnsupportedClass super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 2, attributes: 2 +Constant pool: +{ private final int mValue; descriptor: I flags: (0x0012) ACC_PRIVATE, ACC_FINAL @@ -3658,6 +3812,8 @@ public class com.unsupported.UnsupportedClass this_class: #x // com/unsupported/UnsupportedClass super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 2 +Constant pool: +{ public com.unsupported.UnsupportedClass(int); descriptor: (I)V flags: (0x0001) ACC_PUBLIC diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt index 103e152c7e39..ad413425801b 100644 --- a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt +++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt @@ -7,6 +7,8 @@ public interface android.hosttest.annotation.HostSideTestClassLoadHook extends j this_class: #x // android/hosttest/annotation/HostSideTestClassLoadHook super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ public abstract java.lang.String value(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT @@ -30,6 +32,8 @@ public interface android.hosttest.annotation.HostSideTestIgnore extends java.lan this_class: #x // android/hosttest/annotation/HostSideTestIgnore super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestIgnore.java" RuntimeVisibleAnnotations: @@ -50,6 +54,8 @@ public interface android.hosttest.annotation.HostSideTestKeep extends java.lang. this_class: #x // android/hosttest/annotation/HostSideTestKeep super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestKeep.java" RuntimeVisibleAnnotations: @@ -70,6 +76,8 @@ public interface android.hosttest.annotation.HostSideTestRedirect extends java.l this_class: #x // android/hosttest/annotation/HostSideTestRedirect super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestRedirect.java" RuntimeVisibleAnnotations: @@ -90,6 +98,8 @@ public interface android.hosttest.annotation.HostSideTestRedirectionClass extend this_class: #x // android/hosttest/annotation/HostSideTestRedirectionClass super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ public abstract java.lang.String value(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT @@ -113,6 +123,8 @@ public interface android.hosttest.annotation.HostSideTestRemove extends java.lan this_class: #x // android/hosttest/annotation/HostSideTestRemove super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestRemove.java" RuntimeVisibleAnnotations: @@ -133,6 +145,8 @@ public interface android.hosttest.annotation.HostSideTestStaticInitializerKeep e this_class: #x // android/hosttest/annotation/HostSideTestStaticInitializerKeep super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestStaticInitializerKeep.java" RuntimeVisibleAnnotations: @@ -153,6 +167,8 @@ public interface android.hosttest.annotation.HostSideTestSubstitute extends java this_class: #x // android/hosttest/annotation/HostSideTestSubstitute super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ public abstract java.lang.String suffix(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT @@ -176,6 +192,8 @@ public interface android.hosttest.annotation.HostSideTestThrow extends java.lang this_class: #x // android/hosttest/annotation/HostSideTestThrow super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestThrow.java" RuntimeVisibleAnnotations: @@ -196,6 +214,8 @@ public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends this_class: #x // android/hosttest/annotation/HostSideTestWholeClassKeep super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestWholeClassKeep.java" RuntimeVisibleAnnotations: @@ -216,6 +236,8 @@ public interface android.hosttest.annotation.tests.HostSideTestSuppress extends this_class: #x // android/hosttest/annotation/tests/HostSideTestSuppress super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestSuppress.java" RuntimeVisibleAnnotations: @@ -232,6 +254,8 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Pro this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 3 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Proxy(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -273,6 +297,8 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 3 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -314,6 +340,8 @@ public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 0, attributes: 3 +Constant pool: +{ } SourceFile: "IPretendingAidl.java" NestMembers: @@ -331,6 +359,8 @@ public class com.android.hoststubgen.test.tinyframework.R$Nested this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 2, attributes: 3 +Constant pool: +{ public static int[] ARRAY; descriptor: [I flags: (0x0009) ACC_PUBLIC, ACC_STATIC @@ -376,6 +406,8 @@ public class com.android.hoststubgen.test.tinyframework.R this_class: #x // com/android/hoststubgen/test/tinyframework/R super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 3 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.R(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -396,13 +428,15 @@ InnerClasses: public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.class Compiled from "TinyFrameworkAnnotations.java" -public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations +public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations minor version: 0 major version: 61 - flags: (0x0021) ACC_PUBLIC, ACC_SUPER + flags: (0x0031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 9, attributes: 2 +Constant pool: +{ public int keep; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -433,9 +467,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations x: #x() android.hosttest.annotation.HostSideTestKeep - public int addOne(int); + public final int addOne(int); descriptor: (I)I - flags: (0x0001) ACC_PUBLIC + flags: (0x0011) ACC_PUBLIC, ACC_FINAL Code: stack=2, locals=2, args_size=2 x: iload_1 @@ -505,18 +539,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations; 0 4 1 value I - public static native int nativeAddThree(int); + public static final native int nativeAddThree(int); descriptor: (I)I - flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE + flags: (0x0119) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_NATIVE RuntimeInvisibleAnnotations: x: #x(#x=s#x) android.hosttest.annotation.HostSideTestSubstitute( suffix="_host" ) - private static int nativeAddThree_host(int); + private static final int nativeAddThree_host(int); descriptor: (I)I - flags: (0x000a) ACC_PRIVATE, ACC_STATIC + flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL Code: stack=2, locals=1, args_size=1 x: iload_0 @@ -578,6 +612,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 3, attributes: 2 +Constant pool: +{ public static final java.util.Set<java.lang.Class<?>> sLoadedClasses; descriptor: Ljava/util/Set; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL @@ -640,6 +676,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAn this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 6, attributes: 2 +Constant pool: +{ public int keep; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -764,6 +802,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 2, attributes: 2 +Constant pool: +{ public static boolean sInitialized; descriptor: Z flags: (0x0009) ACC_PUBLIC, ACC_STATIC @@ -818,6 +858,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 2, attributes: 2 +Constant pool: +{ public static boolean sInitialized; descriptor: Z flags: (0x0009) ACC_PUBLIC, ACC_STATIC @@ -878,6 +920,8 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex super_class: #x // java/lang/Enum interfaces: 0, fields: 6, methods: 7, attributes: 3 +Constant pool: +{ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM @@ -1081,6 +1125,8 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple super_class: #x // java/lang/Enum interfaces: 0, fields: 3, methods: 5, attributes: 3 +Constant pool: +{ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM @@ -1202,6 +1248,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTe this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 2 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -1256,6 +1304,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 17, attributes: 1 +Constant pool: +{ public int stub; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -1507,6 +1557,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 8, attributes: 5 +Constant pool: +{ public final java.util.function.Supplier<java.lang.Integer> mSupplier; descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL @@ -1661,6 +1713,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 8, attributes: 5 +Constant pool: +{ public final java.util.function.Supplier<java.lang.Integer> mSupplier; descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL @@ -1816,6 +1870,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 3, attributes: 3 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -1873,6 +1929,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 5, attributes: 5 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -1984,6 +2042,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 14, attributes: 2 +Constant pool: +{ int value; descriptor: I flags: (0x0000) @@ -2157,6 +2217,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 7, attributes: 2 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -2263,6 +2325,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 ex this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 super_class: #x // java/lang/Object interfaces: 1, fields: 1, methods: 3, attributes: 5 +Constant pool: +{ final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC @@ -2328,6 +2392,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 ex this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 3, attributes: 5 +Constant pool: +{ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2(); descriptor: ()V flags: (0x0000) @@ -2382,6 +2448,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 ex this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 super_class: #x // java/lang/Object interfaces: 1, fields: 1, methods: 3, attributes: 5 +Constant pool: +{ final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC @@ -2447,6 +2515,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 ex this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 3, attributes: 5 +Constant pool: +{ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4(); descriptor: ()V flags: (0x0000) @@ -2501,6 +2571,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 1, attributes: 3 +Constant pool: +{ public int value; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -2535,6 +2607,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 1, attributes: 3 +Constant pool: +{ public int value; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -2579,6 +2653,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$Stat this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 3, attributes: 5 +Constant pool: +{ com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1(); descriptor: ()V flags: (0x0000) @@ -2634,6 +2710,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 1, attributes: 3 +Constant pool: +{ public int value; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -2668,6 +2746,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 2, attributes: 3 +Constant pool: +{ public int value; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -2715,6 +2795,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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: 3 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass(int); descriptor: (I)V flags: (0x0001) ACC_PUBLIC @@ -2744,6 +2826,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 4, attributes: 4 +Constant pool: +{ public final java.util.function.Supplier<java.lang.Integer> mSupplier; descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL @@ -2848,6 +2932,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedi this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 2 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedirect(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -2890,6 +2976,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClas this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 2 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -2932,6 +3020,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 2, attributes: 2 +Constant pool: +{ private final int mValue; descriptor: I flags: (0x0012) ACC_PRIVATE, ACC_FINAL @@ -2979,6 +3069,8 @@ public class com.android.hoststubgen.test.tinyframework.packagetest.A this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/A super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.packagetest.A(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3002,6 +3094,8 @@ public class com.android.hoststubgen.test.tinyframework.packagetest.B this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/B super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.packagetest.B(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3025,6 +3119,8 @@ public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/A super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.packagetest.sub.A(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3048,6 +3144,8 @@ public class com.android.hoststubgen.test.tinyframework.packagetest.sub.B this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/B super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.packagetest.sub.B(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3071,6 +3169,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.C1 this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1 super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.C1(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3094,6 +3194,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.C2 extends this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2 super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1 interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.C2(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3117,6 +3219,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.C3 extends this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C3 super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2 interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.C3(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3140,6 +3244,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.CA this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CA super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.CA(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3163,6 +3269,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.CB this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CB super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.CB(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3186,6 +3294,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C1 ex this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1 super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1 interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_C1(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3209,6 +3319,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C2 ex this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2 super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2 interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_C2(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3232,6 +3344,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C3 ex this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3 super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C3 interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_C3(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3255,6 +3369,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_CA ex this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_CA super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CA interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_CA(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3278,6 +3394,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_CB ex this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CB interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_CB(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3301,6 +3419,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_CB_IA this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_CB_IA super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CB interfaces: 1, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_CB_IA(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3324,6 +3444,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1 im this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3347,6 +3469,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1_IA this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA super_class: #x // java/lang/Object interfaces: 2, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1_IA(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3370,6 +3494,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I2 im this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I2(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3393,6 +3519,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3 im this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3416,6 +3544,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3_IA this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3_IA super_class: #x // java/lang/Object interfaces: 2, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3_IA(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3439,6 +3569,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA im this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3462,6 +3594,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA_I1 this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I1 super_class: #x // java/lang/Object interfaces: 2, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA_I1(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3485,6 +3619,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA_I3 this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IA_I3 super_class: #x // java/lang/Object interfaces: 2, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IA_I3(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3508,6 +3644,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IB im this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IB(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3531,6 +3669,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_IB_IA this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_IB_IA super_class: #x // java/lang/Object interfaces: 2, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_IB_IA(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3554,6 +3694,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_None this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_None super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 +Constant pool: +{ public com.android.hoststubgen.test.tinyframework.subclasstest.Class_None(); descriptor: ()V flags: (0x0001) ACC_PUBLIC @@ -3577,6 +3719,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.I1 this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I1 super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 0, attributes: 1 +Constant pool: +{ } SourceFile: "I1.java" ## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I2.class @@ -3588,6 +3732,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.I2 exte this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I2 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 1 +Constant pool: +{ } SourceFile: "I2.java" ## Class: com/android/hoststubgen/test/tinyframework/subclasstest/I3.class @@ -3599,6 +3745,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.I3 exte this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I3 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 0, attributes: 1 +Constant pool: +{ } SourceFile: "I3.java" ## Class: com/android/hoststubgen/test/tinyframework/subclasstest/IA.class @@ -3610,6 +3758,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.IA this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/IA super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 0, attributes: 1 +Constant pool: +{ } SourceFile: "IA.java" ## Class: com/android/hoststubgen/test/tinyframework/subclasstest/IB.class @@ -3621,6 +3771,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.IB this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/IB super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 0, attributes: 1 +Constant pool: +{ } SourceFile: "IB.java" ## Class: com/supported/UnsupportedClass.class @@ -3632,6 +3784,8 @@ public class com.supported.UnsupportedClass this_class: #x // com/supported/UnsupportedClass super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 2, attributes: 2 +Constant pool: +{ private final int mValue; descriptor: I flags: (0x0012) ACC_PRIVATE, ACC_FINAL @@ -3679,6 +3833,8 @@ public class com.unsupported.UnsupportedClass this_class: #x // com/unsupported/UnsupportedClass super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 2 +Constant pool: +{ public com.unsupported.UnsupportedClass(int); descriptor: (I)V flags: (0x0001) ACC_PUBLIC diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.java index 3415deb957ed..674937d15424 100644 --- a/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.java +++ b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.java @@ -28,7 +28,7 @@ import android.hosttest.annotation.HostSideTestThrow; @HostSideTestKeep @HostSideTestClassLoadHook( "com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded") -public class TinyFrameworkAnnotations { +public final class TinyFrameworkAnnotations { @HostSideTestKeep public TinyFrameworkAnnotations() { } @@ -42,7 +42,7 @@ public class TinyFrameworkAnnotations { public int remove; @HostSideTestKeep - public int addOne(int value) { + public final int addOne(int value) { return value + 1; } @@ -61,10 +61,10 @@ public class TinyFrameworkAnnotations { } @HostSideTestSubstitute(suffix = "_host") - public static native int nativeAddThree(int value); + public final static native int nativeAddThree(int value); // This method is private, but at runtime, it'll inherit the visibility of the original method - private static int nativeAddThree_host(int value) { + private final static int nativeAddThree_host(int value) { return value + 3; } diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index 0cbbf6da022b..2c106d31ae59 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -16,8 +16,6 @@ package com.android.server.accessibility.gestures; -import static android.accessibilityservice.AccessibilityTrace.FLAGS_GESTURE; -import static android.accessibilityservice.AccessibilityTrace.FLAGS_INPUT_FILTER; import static android.view.MotionEvent.ACTION_CANCEL; import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_HOVER_ENTER; @@ -86,8 +84,6 @@ import java.util.List; public class TouchExplorer extends BaseEventStreamTransformation implements GestureManifold.Listener { - private static final long LOGGING_FLAGS = FLAGS_GESTURE | FLAGS_INPUT_FILTER; - // Tag for logging received events. private static final String LOG_TAG = "TouchExplorer"; @@ -261,10 +257,6 @@ public class TouchExplorer extends BaseEventStreamTransformation @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { - if (mAms.getTraceManager().isA11yTracingEnabledForTypes(LOGGING_FLAGS)) { - mAms.getTraceManager().logTrace(LOG_TAG + ".onMotionEvent", LOGGING_FLAGS, - "event=" + event + ";rawEvent=" + rawEvent + ";policyFlags=" + policyFlags); - } if (!event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) { super.onMotionEvent(event, rawEvent, policyFlags); return; @@ -323,9 +315,8 @@ public class TouchExplorer extends BaseEventStreamTransformation @Override public void onAccessibilityEvent(AccessibilityEvent event) { - if (mAms.getTraceManager().isA11yTracingEnabledForTypes(LOGGING_FLAGS)) { - mAms.getTraceManager().logTrace(LOG_TAG + ".onAccessibilityEvent", - LOGGING_FLAGS, "event=" + event); + if (DEBUG) { + Slog.v(LOG_TAG, "Received A11y Event. event=" + event); } final int eventType = event.getEventType(); @@ -383,9 +374,9 @@ public class TouchExplorer extends BaseEventStreamTransformation @Override public void onDoubleTapAndHold(MotionEvent event, MotionEvent rawEvent, int policyFlags) { - if (mAms.getTraceManager().isA11yTracingEnabledForTypes(LOGGING_FLAGS)) { - mAms.getTraceManager().logTrace(LOG_TAG + ".onDoubleTapAndHold", LOGGING_FLAGS, - "event=" + event + ";rawEvent=" + rawEvent + ";policyFlags=" + policyFlags); + if (DEBUG) { + Slog.i(LOG_TAG, "Double tap and hold. event=" + + event + ";rawEvent=" + rawEvent + ";policyFlags=" + policyFlags); } if (mDispatcher.longPressWithTouchEvents(event, policyFlags)) { sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); @@ -403,9 +394,9 @@ public class TouchExplorer extends BaseEventStreamTransformation @Override public boolean onDoubleTap(MotionEvent event, MotionEvent rawEvent, int policyFlags) { - if (mAms.getTraceManager().isA11yTracingEnabledForTypes(LOGGING_FLAGS)) { - mAms.getTraceManager().logTrace(LOG_TAG + ".onDoubleTap", LOGGING_FLAGS, - "event=" + event + ";rawEvent=" + rawEvent + ";policyFlags=" + policyFlags); + if (DEBUG) { + Slog.i(LOG_TAG, "Double tap. event=" + + event + ";rawEvent=" + rawEvent + ";policyFlags=" + policyFlags); } mAms.onTouchInteractionEnd(); // Remove pending event deliveries. @@ -463,8 +454,8 @@ public class TouchExplorer extends BaseEventStreamTransformation @Override public boolean onGestureStarted() { - if (mAms.getTraceManager().isA11yTracingEnabledForTypes(LOGGING_FLAGS)) { - mAms.getTraceManager().logTrace(LOG_TAG + ".onGestureStarted", LOGGING_FLAGS); + if (DEBUG) { + Slog.i(LOG_TAG, "Gesture started."); } // We have to perform gesture detection, so // clear the current state and try to detect. @@ -479,9 +470,8 @@ public class TouchExplorer extends BaseEventStreamTransformation @Override public boolean onGestureCompleted(AccessibilityGestureEvent gestureEvent) { - if (mAms.getTraceManager().isA11yTracingEnabledForTypes(LOGGING_FLAGS)) { - mAms.getTraceManager().logTrace(LOG_TAG + ".onGestureCompleted", - LOGGING_FLAGS, "event=" + gestureEvent); + if (DEBUG) { + Slog.i(LOG_TAG, "Gesture completed. gestureEvent=" + gestureEvent); } endGestureDetection(true); mSendTouchInteractionEndDelayed.cancel(); @@ -491,10 +481,11 @@ public class TouchExplorer extends BaseEventStreamTransformation @Override public boolean onGestureCancelled(MotionEvent event, MotionEvent rawEvent, int policyFlags) { - if (mAms.getTraceManager().isA11yTracingEnabledForTypes(LOGGING_FLAGS)) { - mAms.getTraceManager().logTrace(LOG_TAG + ".onGestureCancelled", LOGGING_FLAGS, - "event=" + event + ";rawEvent=" + rawEvent + ";policyFlags=" + policyFlags); + if (DEBUG) { + Slog.i(LOG_TAG, "Gesture cancelled. event=" + + event + ";rawEvent=" + rawEvent + ";policyFlags=" + policyFlags); } + if (mState.isGestureDetecting()) { endGestureDetection(event.getActionMasked() == ACTION_UP); return true; diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 0e2e50589217..a37b2b926c9c 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -612,7 +612,7 @@ public class CompanionDeviceManagerService extends SystemService { @Override public void enablePermissionsSync(int associationId) { - if (getCallingUid() != SYSTEM_UID) { + if (UserHandle.getAppId(Binder.getCallingUid()) == SYSTEM_UID) { throw new SecurityException("Caller must be system UID"); } mSystemDataTransferProcessor.enablePermissionsSync(associationId); @@ -620,7 +620,7 @@ public class CompanionDeviceManagerService extends SystemService { @Override public void disablePermissionsSync(int associationId) { - if (getCallingUid() != SYSTEM_UID) { + if (UserHandle.getAppId(Binder.getCallingUid()) == SYSTEM_UID) { throw new SecurityException("Caller must be system UID"); } mSystemDataTransferProcessor.disablePermissionsSync(associationId); @@ -628,7 +628,7 @@ public class CompanionDeviceManagerService extends SystemService { @Override public PermissionSyncRequest getPermissionSyncRequest(int associationId) { - if (getCallingUid() != SYSTEM_UID) { + if (UserHandle.getAppId(Binder.getCallingUid()) == SYSTEM_UID) { throw new SecurityException("Caller must be system UID"); } return mSystemDataTransferProcessor.getPermissionSyncRequest(associationId); @@ -704,7 +704,7 @@ public class CompanionDeviceManagerService extends SystemService { @Override public byte[] getBackupPayload(int userId) { - if (getCallingUid() != SYSTEM_UID) { + if (UserHandle.getAppId(Binder.getCallingUid()) == SYSTEM_UID) { throw new SecurityException("Caller must be system"); } return mBackupRestoreProcessor.getBackupPayload(userId); @@ -712,7 +712,7 @@ public class CompanionDeviceManagerService extends SystemService { @Override public void applyRestoredPayload(byte[] payload, int userId) { - if (getCallingUid() != SYSTEM_UID) { + if (UserHandle.getAppId(Binder.getCallingUid()) == SYSTEM_UID) { throw new SecurityException("Caller must be system"); } mBackupRestoreProcessor.applyRestoredPayload(payload, userId); diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java index ba391d0a9995..5aa2a6b60106 100644 --- a/services/core/java/com/android/server/appop/HistoricalRegistry.java +++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java @@ -205,18 +205,8 @@ final class HistoricalRegistry { mContext = context; if (Flags.enableSqliteAppopsAccesses()) { mDiscreteRegistry = new DiscreteOpsSqlRegistry(context); - if (DiscreteOpsXmlRegistry.getDiscreteOpsDir().exists()) { - DiscreteOpsSqlRegistry sqlRegistry = (DiscreteOpsSqlRegistry) mDiscreteRegistry; - DiscreteOpsXmlRegistry xmlRegistry = new DiscreteOpsXmlRegistry(context); - DiscreteOpsMigrationHelper.migrateDiscreteOpsToSqlite(xmlRegistry, sqlRegistry); - } } else { mDiscreteRegistry = new DiscreteOpsXmlRegistry(context); - if (DiscreteOpsDbHelper.getDatabaseFile().exists()) { // roll-back sqlite - DiscreteOpsSqlRegistry sqlRegistry = new DiscreteOpsSqlRegistry(context); - DiscreteOpsXmlRegistry xmlRegistry = (DiscreteOpsXmlRegistry) mDiscreteRegistry; - DiscreteOpsMigrationHelper.migrateDiscreteOpsToXml(sqlRegistry, xmlRegistry); - } } } @@ -267,6 +257,19 @@ final class HistoricalRegistry { } } } + if (Flags.enableSqliteAppopsAccesses()) { + if (DiscreteOpsXmlRegistry.getDiscreteOpsDir().exists()) { + DiscreteOpsSqlRegistry sqlRegistry = (DiscreteOpsSqlRegistry) mDiscreteRegistry; + DiscreteOpsXmlRegistry xmlRegistry = new DiscreteOpsXmlRegistry(mContext); + DiscreteOpsMigrationHelper.migrateDiscreteOpsToSqlite(xmlRegistry, sqlRegistry); + } + } else { + if (DiscreteOpsDbHelper.getDatabaseFile().exists()) { // roll-back sqlite + DiscreteOpsSqlRegistry sqlRegistry = new DiscreteOpsSqlRegistry(mContext); + DiscreteOpsXmlRegistry xmlRegistry = (DiscreteOpsXmlRegistry) mDiscreteRegistry; + DiscreteOpsMigrationHelper.migrateDiscreteOpsToXml(sqlRegistry, xmlRegistry); + } + } } private boolean isPersistenceInitializedMLocked() { diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java index e51289b6990a..6ad7ea7b768f 100644 --- a/services/core/java/com/android/server/media/quality/MediaQualityService.java +++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java @@ -1385,7 +1385,7 @@ public class MediaQualityService extends SystemService { try { if (mMediaQuality != null) { if (mMediaQuality.isAutoPqSupported()) { - mMediaQuality.getAutoPqEnabled(); + return mMediaQuality.getAutoPqEnabled(); } } } catch (RemoteException e) { @@ -1417,7 +1417,7 @@ public class MediaQualityService extends SystemService { try { if (mMediaQuality != null) { if (mMediaQuality.isAutoSrSupported()) { - mMediaQuality.getAutoSrEnabled(); + return mMediaQuality.getAutoSrEnabled(); } } } catch (RemoteException e) { @@ -1449,7 +1449,7 @@ public class MediaQualityService extends SystemService { try { if (mMediaQuality != null) { if (mMediaQuality.isAutoAqSupported()) { - mMediaQuality.getAutoAqEnabled(); + return mMediaQuality.getAutoAqEnabled(); } } } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index ef39f1811876..588e87924b7d 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -356,6 +356,7 @@ import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.internal.util.function.TriPredicate; import com.android.internal.widget.LockPatternUtils; +import com.android.modules.expresslog.Counter; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; import com.android.server.DeviceIdleInternal; @@ -762,7 +763,7 @@ public class NotificationManagerService extends SystemService { private int mWarnRemoteViewsSizeBytes; private int mStripRemoteViewsSizeBytes; - private String[] mDefaultUnsupportedAdjustments; + protected String[] mDefaultUnsupportedAdjustments; @VisibleForTesting protected boolean mShowReviewPermissionsNotification; @@ -4377,8 +4378,8 @@ public class NotificationManagerService extends SystemService { public @NonNull List<String> getUnsupportedAdjustmentTypes() { checkCallerIsSystemOrSystemUiOrShell(); synchronized (mNotificationLock) { - return new ArrayList(mAssistants.mNasUnsupported.getOrDefault( - UserHandle.getUserId(Binder.getCallingUid()), new HashSet<>())); + return new ArrayList(mAssistants.getUnsupportedAdjustments( + UserHandle.getUserId(Binder.getCallingUid()))); } } @@ -7136,6 +7137,13 @@ public class NotificationManagerService extends SystemService { Slog.e(TAG, "exiting pullStats: bad request"); return 0; } + + @Override + public void incrementCounter(String metricId) { + if (android.app.Flags.nmBinderPerfLogNmThrottling() && metricId != null) { + Counter.logIncrementWithUid(metricId, Binder.getCallingUid()); + } + } }; private void handleNotificationPermissionChange(String pkg, @UserIdInt int userId) { @@ -7214,6 +7222,7 @@ public class NotificationManagerService extends SystemService { toRemove.add(potentialKey); } if (notificationClassification() && adjustments.containsKey(KEY_TYPE)) { + mAssistants.setNasUnsupportedDefaults(r.getSbn().getNormalizedUserId()); if (!mAssistants.isAdjustmentKeyTypeAllowed(adjustments.getInt(KEY_TYPE))) { toRemove.add(potentialKey); } else if (notificationClassificationUi() @@ -11867,9 +11876,9 @@ public class NotificationManagerService extends SystemService { static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants"; private static final String ATT_TYPES = "types"; - private static final String ATT_DENIED = "denied_adjustments"; + private static final String ATT_DENIED = "user_denied_adjustments"; private static final String ATT_ENABLED_TYPES = "enabled_key_types"; - private static final String ATT_NAS_UNSUPPORTED = "unsupported_adjustments"; + private static final String ATT_NAS_UNSUPPORTED = "nas_unsupported_adjustments"; private static final String ATT_TYPES_DENIED_APPS = "types_denied_apps"; private final Object mLock = new Object(); @@ -11965,9 +11974,6 @@ public class NotificationManagerService extends SystemService { } } else { mAllowedAdjustmentKeyTypes.addAll(List.of(DEFAULT_ALLOWED_ADJUSTMENT_KEY_TYPES)); - if (mDefaultUnsupportedAdjustments != null) { - mAllowedAdjustments.removeAll(List.of(mDefaultUnsupportedAdjustments)); - } } } @@ -12487,7 +12493,7 @@ public class NotificationManagerService extends SystemService { } } else { if (android.service.notification.Flags.notificationClassification()) { - mNasUnsupported.put(userId, new HashSet<>()); + setNasUnsupportedDefaults(userId); } } super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, userSet); @@ -12528,8 +12534,8 @@ public class NotificationManagerService extends SystemService { if (!android.service.notification.Flags.notificationClassification()) { return; } - HashSet<String> disabledAdjustments = - mNasUnsupported.getOrDefault(info.userid, new HashSet<>()); + setNasUnsupportedDefaults(info.userid); + HashSet<String> disabledAdjustments = mNasUnsupported.get(info.userid); if (supported) { disabledAdjustments.remove(key); } else { @@ -12545,7 +12551,15 @@ public class NotificationManagerService extends SystemService { if (!android.service.notification.Flags.notificationClassification()) { return new HashSet<>(); } - return mNasUnsupported.getOrDefault(userId, new HashSet<>()); + setNasUnsupportedDefaults(userId); + return mNasUnsupported.get(userId); + } + + private void setNasUnsupportedDefaults(@UserIdInt int userId) { + if (mNasUnsupported != null && !mNasUnsupported.containsKey(userId)) { + mNasUnsupported.put(userId, new HashSet(List.of(mDefaultUnsupportedAdjustments))); + handleSavePolicyFile(); + } } @Override @@ -12658,7 +12672,7 @@ public class NotificationManagerService extends SystemService { List<String> unsupportedAdjustments = new ArrayList( mNasUnsupported.getOrDefault( UserHandle.getUserId(Binder.getCallingUid()), - new HashSet<>()) + new HashSet(List.of(mDefaultUnsupportedAdjustments))) ); bundlesAllowed = !unsupportedAdjustments.contains(Adjustment.KEY_TYPE); } diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 4cca85590967..b043d13f9da0 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -856,39 +856,42 @@ final class InstallPackageHelper { if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token); final boolean succeeded = request.getReturnCode() == PackageManager.INSTALL_SUCCEEDED; - if (succeeded && doRestore) { - // Pass responsibility to the Backup Manager. It will perform a - // restore if appropriate, then pass responsibility back to the - // Package Manager to run the post-install observer callbacks - // and broadcasts. - request.closeFreezer(); - doRestore = performBackupManagerRestore(userId, token, request); - } - - // If this is an update to a package that might be potentially downgraded, then we - // need to check with the rollback manager whether there's any userdata that might - // need to be snapshotted or restored for the package. - // - // TODO(narayan): Get this working for cases where userId == UserHandle.USER_ALL. - if (succeeded && !doRestore && update) { - doRestore = performRollbackManagerRestore(userId, token, request); - } - - if (succeeded && doRestore && !request.hasPostInstallRunnable()) { - boolean hasNeverBeenRestored = - packageSetting != null && packageSetting.isPendingRestore(); - request.setPostInstallRunnable(() -> { - // Permissions should be restored on each user that has the app installed for the - // first time, unless it's an unarchive install for an archived app, in which case - // the permissions should be restored on each user that has the app updated. - int[] userIdsToRestorePermissions = hasNeverBeenRestored - ? request.getUpdateBroadcastUserIds() - : request.getFirstTimeBroadcastUserIds(); - for (int restorePermissionUserId : userIdsToRestorePermissions) { - mPm.restorePermissionsAndUpdateRolesForNewUserInstall(request.getName(), - restorePermissionUserId); - } - }); + if (succeeded) { + request.onRestoreStarted(); + if (doRestore) { + // Pass responsibility to the Backup Manager. It will perform a + // restore if appropriate, then pass responsibility back to the + // Package Manager to run the post-install observer callbacks + // and broadcasts. + doRestore = performBackupManagerRestore(userId, token, request); + } + + // If this is an update to a package that might be potentially downgraded, then we + // need to check with the rollback manager whether there's any userdata that might + // need to be snapshotted or restored for the package. + // + // TODO(narayan): Get this working for cases where userId == UserHandle.USER_ALL. + if (!doRestore && update) { + doRestore = performRollbackManagerRestore(userId, token, request); + } + + if (doRestore && !request.hasPostInstallRunnable()) { + boolean hasNeverBeenRestored = + packageSetting != null && packageSetting.isPendingRestore(); + request.setPostInstallRunnable(() -> { + // Permissions should be restored on each user that has the app installed for + // the first time, unless it's an unarchive install for an archived app, in + // which case the permissions should be restored on each user that has the + // app updated. + int[] userIdsToRestorePermissions = hasNeverBeenRestored + ? request.getUpdateBroadcastUserIds() + : request.getFirstTimeBroadcastUserIds(); + for (int restorePermissionUserId : userIdsToRestorePermissions) { + mPm.restorePermissionsAndUpdateRolesForNewUserInstall(request.getName(), + restorePermissionUserId); + } + }); + } } if (doRestore) { @@ -898,8 +901,11 @@ final class InstallPackageHelper { } } } else { - // No restore possible, or the Backup Manager was mysteriously not - // available -- just fire the post-install work request directly. + // No restore possible, or the Backup Manager was mysteriously not available. + // we don't need to wait for restore to complete before closing the freezer, + // so we can close the freezer right away. + // Also just fire the post-install work request directly. + request.closeFreezer(); if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token); Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token); diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java index c96c160deb0f..fbf5db5d9635 100644 --- a/services/core/java/com/android/server/pm/InstallRequest.java +++ b/services/core/java/com/android/server/pm/InstallRequest.java @@ -1016,6 +1016,18 @@ final class InstallRequest { } } + public void onRestoreStarted() { + if (mPackageMetrics != null) { + mPackageMetrics.onStepStarted(PackageMetrics.STEP_RESTORE); + } + } + + public void onRestoreFinished() { + if (mPackageMetrics != null) { + mPackageMetrics.onStepFinished(PackageMetrics.STEP_RESTORE); + } + } + public void onDexoptFinished(DexoptResult dexoptResult) { // Only report external profile warnings when installing from adb. The goal is to warn app // developers if they have provided bad external profiles, so it's not beneficial to report diff --git a/services/core/java/com/android/server/pm/PackageHandler.java b/services/core/java/com/android/server/pm/PackageHandler.java index 9916be680374..7b1eb58d25f4 100644 --- a/services/core/java/com/android/server/pm/PackageHandler.java +++ b/services/core/java/com/android/server/pm/PackageHandler.java @@ -99,6 +99,7 @@ final class PackageHandler extends Handler { } break; } + request.onRestoreFinished(); request.closeFreezer(); request.onInstallCompleted(); request.runPostInstallRunnable(); diff --git a/services/core/java/com/android/server/pm/PackageMetrics.java b/services/core/java/com/android/server/pm/PackageMetrics.java index 856d6a726da5..994ee421790c 100644 --- a/services/core/java/com/android/server/pm/PackageMetrics.java +++ b/services/core/java/com/android/server/pm/PackageMetrics.java @@ -72,6 +72,7 @@ final class PackageMetrics { public static final int STEP_COMMIT = 4; public static final int STEP_DEXOPT = 5; public static final int STEP_FREEZE_INSTALL = 6; + public static final int STEP_RESTORE = 7; @IntDef(prefix = {"STEP_"}, value = { STEP_PREPARE, @@ -79,7 +80,8 @@ final class PackageMetrics { STEP_RECONCILE, STEP_COMMIT, STEP_DEXOPT, - STEP_FREEZE_INSTALL + STEP_FREEZE_INSTALL, + STEP_RESTORE }) @Retention(RetentionPolicy.SOURCE) public @interface StepInt { diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index b7b4cc0b6861..48dd2ebc7044 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -87,6 +87,7 @@ import android.service.quicksettings.TileService; import android.text.TextUtils; import android.util.ArrayMap; import android.util.IndentingPrintWriter; +import android.util.IntArray; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; @@ -124,6 +125,7 @@ import com.android.server.policy.GlobalActionsProvider; import com.android.server.power.ShutdownCheckPoints; import com.android.server.power.ShutdownThread; import com.android.server.wm.ActivityTaskManagerInternal; +import com.android.systemui.shared.Flags; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -341,15 +343,19 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @Override public void onDisplayAdded(int displayId) { - synchronized (mLock) { - mDisplayUiState.put(displayId, new UiState()); + if (Flags.statusBarConnectedDisplays()) { + synchronized (mLock) { + mDisplayUiState.put(displayId, new UiState()); + } } } @Override public void onDisplayRemoved(int displayId) { - synchronized (mLock) { - mDisplayUiState.remove(displayId); + if (Flags.statusBarConnectedDisplays()) { + synchronized (mLock) { + mDisplayUiState.remove(displayId); + } } } @@ -1320,53 +1326,66 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D return mTracingEnabled; } - // TODO(b/117478341): make it aware of multi-display if needed. @Override public void disable(int what, IBinder token, String pkg) { disableForUser(what, token, pkg, mCurrentUserId); } - // TODO(b/117478341): make it aware of multi-display if needed. + /** + * Disable additional status bar features for user for all displays. Pass the bitwise-or of the + * {@code #DISABLE_*} flags. To re-enable everything, pass {@code #DISABLE_NONE}. + * + * Warning: Only pass {@code #DISABLE_*} flags into this function, do not use + * {@code #DISABLE2_*} flags. + */ @Override public void disableForUser(int what, IBinder token, String pkg, int userId) { enforceStatusBar(); enforceValidCallingUser(); synchronized (mLock) { - disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 1); + IntArray displayIds = new IntArray(); + for (int i = 0; i < mDisplayUiState.size(); i++) { + displayIds.add(mDisplayUiState.keyAt(i)); + } + disableLocked(displayIds, userId, what, token, pkg, 1); } } - // TODO(b/117478341): make it aware of multi-display if needed. /** - * Disable additional status bar features. Pass the bitwise-or of the DISABLE2_* flags. - * To re-enable everything, pass {@link #DISABLE2_NONE}. + * Disable additional status bar features. Pass the bitwise-or of the {@code #DISABLE2_*} flags. + * To re-enable everything, pass {@code #DISABLE2_NONE}. * - * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags. + * Warning: Only pass {@code #DISABLE2_*} flags into this function, do not use + * {@code #DISABLE_*} flags. */ @Override public void disable2(int what, IBinder token, String pkg) { disable2ForUser(what, token, pkg, mCurrentUserId); } - // TODO(b/117478341): make it aware of multi-display if needed. /** - * Disable additional status bar features for a given user. Pass the bitwise-or of the - * DISABLE2_* flags. To re-enable everything, pass {@link #DISABLE_NONE}. + * Disable additional status bar features for a given user for all displays. Pass the bitwise-or + * of the {@code #DISABLE2_*} flags. To re-enable everything, pass {@code #DISABLE2_NONE}. * - * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags. + * Warning: Only pass {@code #DISABLE2_*} flags into this function, do not use + * {@code #DISABLE_*} flags. */ @Override public void disable2ForUser(int what, IBinder token, String pkg, int userId) { enforceStatusBar(); synchronized (mLock) { - disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 2); + IntArray displayIds = new IntArray(); + for (int i = 0; i < mDisplayUiState.size(); i++) { + displayIds.add(mDisplayUiState.keyAt(i)); + } + disableLocked(displayIds, userId, what, token, pkg, 2); } } - private void disableLocked(int displayId, int userId, int what, IBinder token, String pkg, - int whichFlag) { + private void disableLocked(IntArray displayIds, int userId, int what, IBinder token, + String pkg, int whichFlag) { // It's important that the the callback and the call to mBar get done // in the same order when multiple threads are calling this function // so they are paired correctly. The messages on the handler will be @@ -1376,18 +1395,27 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D // Ensure state for the current user is applied, even if passed a non-current user. final int net1 = gatherDisableActionsLocked(mCurrentUserId, 1); final int net2 = gatherDisableActionsLocked(mCurrentUserId, 2); - final UiState state = getUiState(displayId); - if (!state.disableEquals(net1, net2)) { - state.setDisabled(net1, net2); - mHandler.post(() -> mNotificationDelegate.onSetDisabled(net1)); - IStatusBar bar = mBar; - if (bar != null) { - try { - bar.disable(displayId, net1, net2); - } catch (RemoteException ex) { + boolean shouldCallNotificationOnSetDisabled = false; + IStatusBar bar = mBar; + for (int displayId : displayIds.toArray()) { + final UiState state = getUiState(displayId); + if (!state.disableEquals(net1, net2)) { + shouldCallNotificationOnSetDisabled = true; + state.setDisabled(net1, net2); + if (bar != null) { + try { + // TODO(b/388244660): Create IStatusBar#disableForAllDisplays to avoid + // multiple IPC calls. + bar.disable(displayId, net1, net2); + } catch (RemoteException ex) { + Slog.e(TAG, "Unable to disable Status bar.", ex); + } } } } + if (shouldCallNotificationOnSetDisabled) { + mHandler.post(() -> mNotificationDelegate.onSetDisabled(net1)); + } } /** @@ -1539,7 +1567,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D if (SPEW) Slog.d(TAG, "setDisableFlags(0x" + Integer.toHexString(flags) + ")"); synchronized (mLock) { - disableLocked(displayId, mCurrentUserId, flags, mSysUiVisToken, cause, 1); + disableLocked(IntArray.wrap(new int[]{displayId}), mCurrentUserId, flags, + mSysUiVisToken, cause, 1); } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 42a47d4a037e..4300b60034a0 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -784,11 +784,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @NonNull final AppCompatController mAppCompatController; - // Whether the activity is eligible to be letterboxed for fixed orientation with respect to its - // requested orientation, even when it's letterbox for another reason (e.g., size compat mode) - // and therefore #isLetterboxedForFixedOrientationAndAspectRatio returns false. - private boolean mIsEligibleForFixedOrientationLetterbox; - /** * Whether the activity is to be displayed. See {@link android.R.attr#windowNoDisplay}. */ @@ -2829,7 +2824,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } void removeStartingWindow() { - boolean prevEligibleForLetterboxEducation = isEligibleForLetterboxEducation(); + final AppCompatLetterboxPolicy letterboxPolicy = mAppCompatController + .getAppCompatLetterboxPolicy(); + boolean prevEligibleForLetterboxEducation = + letterboxPolicy.isEligibleForLetterboxEducation(); if (mStartingData != null && mStartingData.mRemoveAfterTransaction == AFTER_TRANSITION_FINISH) { @@ -2842,8 +2840,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A removeStartingWindowAnimation(true /* prepareAnimation */); final Task task = getTask(); - if (prevEligibleForLetterboxEducation != isEligibleForLetterboxEducation() - && task != null) { + if (task != null && prevEligibleForLetterboxEducation + != letterboxPolicy.isEligibleForLetterboxEducation()) { // Trigger TaskInfoChanged to update the letterbox education. task.dispatchTaskInfoChangedIfNeeded(true /* force */); } @@ -8443,7 +8441,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final AppCompatAspectRatioPolicy aspectRatioPolicy = mAppCompatController.getAspectRatioPolicy(); aspectRatioPolicy.reset(); - mIsEligibleForFixedOrientationLetterbox = false; + mAppCompatController.getAppCompatLetterboxPolicy() + .resetFixedOrientationLetterboxEligibility(); mResolveConfigHint.resolveTmpOverrides(mDisplayContent, newParentConfiguration, isFixedRotationTransforming()); @@ -8780,28 +8779,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } /** - * Whether this activity is eligible for letterbox eduction. - * - * <p>Conditions that need to be met: - * - * <ul> - * <li>{@link AppCompatConfiguration#getIsEducationEnabled} is true. - * <li>The activity is eligible for fixed orientation letterbox. - * <li>The activity is in fullscreen. - * <li>The activity is portrait-only. - * <li>The activity doesn't have a starting window (education should only be displayed - * once the starting window is removed in {@link #removeStartingWindow}). - * </ul> - */ - boolean isEligibleForLetterboxEducation() { - return mWmService.mAppCompatConfiguration.getIsEducationEnabled() - && mIsEligibleForFixedOrientationLetterbox - && getWindowingMode() == WINDOWING_MODE_FULLSCREEN - && getRequestedConfigurationOrientation() == ORIENTATION_PORTRAIT - && mStartingWindow == null; - } - - /** * In some cases, applying insets to bounds changes the orientation. For example, if a * close-to-square display rotates to portrait to respect a portrait orientation activity, after * insets such as the status and nav bars are applied, the activity may actually have a @@ -8905,11 +8882,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // If the activity requires a different orientation (either by override or activityInfo), // make it fit the available bounds by scaling down its bounds. final int forcedOrientation = getRequestedConfigurationOrientation(); + final boolean isEligibleForFixedOrientationLetterbox = mAppCompatController + .getAppCompatLetterboxPolicy() + .resolveFixedOrientationLetterboxEligibility(forcedOrientation, parentOrientation); - mIsEligibleForFixedOrientationLetterbox = forcedOrientation != ORIENTATION_UNDEFINED - && forcedOrientation != parentOrientation; - - if (!mIsEligibleForFixedOrientationLetterbox && (forcedOrientation == ORIENTATION_UNDEFINED + if (!isEligibleForFixedOrientationLetterbox && (forcedOrientation == ORIENTATION_UNDEFINED || orientationRespectedWithInsets)) { return; } @@ -10105,7 +10082,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A proto.write(OVERRIDE_ORIENTATION, getOverrideOrientation()); proto.write(SHOULD_SEND_COMPAT_FAKE_FOCUS, shouldSendCompatFakeFocus()); final AppCompatCameraOverrides cameraOverrides = - mAppCompatController.getAppCompatCameraOverrides(); + mAppCompatController.getCameraOverrides(); proto.write(SHOULD_FORCE_ROTATE_FOR_CAMERA_COMPAT, cameraOverrides.shouldForceRotateForCameraCompat()); proto.write(SHOULD_REFRESH_ACTIVITY_FOR_CAMERA_COMPAT, diff --git a/services/core/java/com/android/server/wm/ActivityRefresher.java b/services/core/java/com/android/server/wm/ActivityRefresher.java index 597f75a52f1c..25e38b307b5e 100644 --- a/services/core/java/com/android/server/wm/ActivityRefresher.java +++ b/services/core/java/com/android/server/wm/ActivityRefresher.java @@ -77,10 +77,10 @@ class ActivityRefresher { final boolean cycleThroughStop = mWmService.mAppCompatConfiguration .isCameraCompatRefreshCycleThroughStopEnabled() - && !activity.mAppCompatController.getAppCompatCameraOverrides() + && !activity.mAppCompatController.getCameraOverrides() .shouldRefreshActivityViaPauseForCameraCompat(); - activity.mAppCompatController.getAppCompatCameraOverrides().setIsRefreshRequested(true); + activity.mAppCompatController.getCameraOverrides().setIsRefreshRequested(true); ProtoLog.v(WM_DEBUG_STATES, "Refreshing activity for freeform camera compatibility treatment, " + "activityRecord=%s", activity); @@ -97,25 +97,25 @@ class ActivityRefresher { } }, REFRESH_CALLBACK_TIMEOUT_MS); } catch (RemoteException e) { - activity.mAppCompatController.getAppCompatCameraOverrides() + activity.mAppCompatController.getCameraOverrides() .setIsRefreshRequested(false); } } boolean isActivityRefreshing(@NonNull ActivityRecord activity) { - return activity.mAppCompatController.getAppCompatCameraOverrides().isRefreshRequested(); + return activity.mAppCompatController.getCameraOverrides().isRefreshRequested(); } void onActivityRefreshed(@NonNull ActivityRecord activity) { // TODO(b/333060789): can we tell that refresh did not happen by observing the activity // state? - activity.mAppCompatController.getAppCompatCameraOverrides().setIsRefreshRequested(false); + activity.mAppCompatController.getCameraOverrides().setIsRefreshRequested(false); } private boolean shouldRefreshActivity(@NonNull ActivityRecord activity, @NonNull Configuration newConfig, @NonNull Configuration lastReportedConfig) { return mWmService.mAppCompatConfiguration.isCameraCompatRefreshEnabled() - && activity.mAppCompatController.getAppCompatCameraOverrides() + && activity.mAppCompatController.getCameraOverrides() .shouldRefreshActivityForCameraCompat() && ArrayUtils.find(mEvaluators.toArray(), evaluator -> ((Evaluator) evaluator) diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index bdbd0d15d982..8e4d4be693f8 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -124,6 +124,7 @@ import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.IBinder; +import android.os.OperationCanceledException; import android.os.RemoteException; import android.os.Trace; import android.os.UserHandle; @@ -3246,11 +3247,14 @@ class ActivityStarter { private void sendCanNotEmbedActivityError(TaskFragment taskFragment, @EmbeddingCheckResult int result) { final String errMsg; - switch(result) { + boolean fatalError = true; + switch (result) { case EMBEDDING_DISALLOWED_NEW_TASK: { errMsg = "Cannot embed " + mStartActivity + " that launched on another task" + ",mLaunchMode=" + launchModeToString(mLaunchMode) + ",mLaunchFlag=" + Integer.toHexString(mLaunchFlags); + // This is a known possible scenario, which should not be a fatal error. + fatalError = false; break; } case EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION: { @@ -3270,7 +3274,8 @@ class ActivityStarter { mService.mWindowOrganizerController.sendTaskFragmentOperationFailure( taskFragment.getTaskFragmentOrganizer(), mRequest.errorCallbackToken, taskFragment, OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT, - new SecurityException(errMsg)); + fatalError ? new SecurityException(errMsg) + : new OperationCanceledException(errMsg)); } else { // If the taskFragment is not organized, just dump error message as warning logs. Slog.w(TAG, errMsg); diff --git a/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java b/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java index 086b11c25a8d..fa04955f975b 100644 --- a/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java +++ b/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java @@ -272,7 +272,7 @@ class AppCompatAspectRatioOverrides { final boolean isLandscape = isFixedOrientationLandscape( mActivityRecord.getOverrideOrientation()); final AppCompatCameraOverrides cameraOverrides = - mActivityRecord.mAppCompatController.getAppCompatCameraOverrides(); + mActivityRecord.mAppCompatController.getCameraOverrides(); // Don't resize to split screen size when in book mode if letterbox position is centered return (isBookMode && isNotCenteredHorizontally || isTabletopMode && isLandscape) || cameraOverrides.isCameraCompatSplitScreenAspectRatioAllowed() diff --git a/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java b/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java index 6074608422d1..276c7d2cbaa0 100644 --- a/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java +++ b/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java @@ -277,7 +277,7 @@ class AppCompatCameraPolicy { */ static boolean shouldOverrideMinAspectRatioForCamera(@NonNull ActivityRecord activityRecord) { return AppCompatCameraPolicy.isCameraRunningAndWindowingModeEligible(activityRecord) - && activityRecord.mAppCompatController.getAppCompatCameraOverrides() + && activityRecord.mAppCompatController.getCameraOverrides() .isOverrideMinAspectRatioForCameraEnabled(); } } diff --git a/services/core/java/com/android/server/wm/AppCompatController.java b/services/core/java/com/android/server/wm/AppCompatController.java index cc9cd90fae06..b7d8aff66ec8 100644 --- a/services/core/java/com/android/server/wm/AppCompatController.java +++ b/services/core/java/com/android/server/wm/AppCompatController.java @@ -94,8 +94,8 @@ class AppCompatController { } @NonNull - AppCompatCameraOverrides getAppCompatCameraOverrides() { - return mAppCompatOverrides.getAppCompatCameraOverrides(); + AppCompatCameraOverrides getCameraOverrides() { + return mAppCompatOverrides.getCameraOverrides(); } @NonNull diff --git a/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java b/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java index 449458665b63..6a8040ab5248 100644 --- a/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java +++ b/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java @@ -16,6 +16,9 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; +import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; @@ -28,6 +31,7 @@ import static com.android.server.wm.AppCompatLetterboxUtils.calculateLetterboxPo import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.res.Configuration.Orientation; import android.graphics.Point; import android.graphics.Rect; import android.view.SurfaceControl; @@ -55,6 +59,11 @@ class AppCompatLetterboxPolicy { private boolean mLastShouldShowLetterboxUi; + // Whether the activity is eligible to be letterboxed for fixed orientation with respect to its + // requested orientation, even when it's letterbox for another reason (e.g., size compat mode) + // and therefore #isLetterboxedForFixedOrientationAndAspectRatio returns false. + private boolean mIsEligibleForFixedOrientationLetterbox; + AppCompatLetterboxPolicy(@NonNull ActivityRecord activityRecord, @NonNull AppCompatConfiguration appCompatConfiguration) { mActivityRecord = activityRecord; @@ -66,6 +75,10 @@ class AppCompatLetterboxPolicy { mAppCompatConfiguration = appCompatConfiguration; } + void resetFixedOrientationLetterboxEligibility() { + mIsEligibleForFixedOrientationLetterbox = false; + } + /** Cleans up {@link Letterbox} if it exists.*/ void stop() { mLetterboxPolicyState.stop(); @@ -91,6 +104,43 @@ class AppCompatLetterboxPolicy { mLetterboxPolicyState.getLetterboxInnerBounds(outBounds); } + /** + * Checks if the current activity is eligible to be letterboxed because of a fixed orientation. + * + * @param forcedOrientation The requeste orientation + * @param parentOrientation The orientation of the parent container. + * @return {@code true} if the activity can be letterboxed because of the requested fixed + * orientation. + */ + boolean resolveFixedOrientationLetterboxEligibility(@Orientation int forcedOrientation, + @Orientation int parentOrientation) { + mIsEligibleForFixedOrientationLetterbox = forcedOrientation != ORIENTATION_UNDEFINED + && forcedOrientation != parentOrientation; + return mIsEligibleForFixedOrientationLetterbox; + } + + /** + * Whether this activity is eligible for letterbox eduction. + * + * <p>Conditions that need to be met: + * + * <ul> + * <li>{@link AppCompatConfiguration#getIsEducationEnabled} is true. + * <li>The activity is eligible for fixed orientation letterbox. + * <li>The activity is in fullscreen. + * <li>The activity is portrait-only. + * <li>The activity doesn't have a starting window (education should only be displayed + * once the starting window is removed in {@link #removeStartingWindow}). + * </ul> + */ + boolean isEligibleForLetterboxEducation() { + return mAppCompatConfiguration.getIsEducationEnabled() + && mIsEligibleForFixedOrientationLetterbox + && mActivityRecord.getWindowingMode() == WINDOWING_MODE_FULLSCREEN + && mActivityRecord.getRequestedConfigurationOrientation() == ORIENTATION_PORTRAIT + && mActivityRecord.mStartingWindow == null; + } + @Nullable LetterboxDetails getLetterboxDetails() { final WindowState w = mActivityRecord.findMainWindow(); diff --git a/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java b/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java index 6202f8070dd4..35fa39dab900 100644 --- a/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java +++ b/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java @@ -100,7 +100,7 @@ class AppCompatOrientationPolicy { } if (displayContent != null - && mAppCompatOverrides.getAppCompatCameraOverrides() + && mAppCompatOverrides.getCameraOverrides() .isOverrideOrientationOnlyForCameraEnabled() && !AppCompatCameraPolicy .isActivityEligibleForOrientationOverride(mActivityRecord)) { diff --git a/services/core/java/com/android/server/wm/AppCompatOverrides.java b/services/core/java/com/android/server/wm/AppCompatOverrides.java index 2d0ff9be2133..811a39c6a78e 100644 --- a/services/core/java/com/android/server/wm/AppCompatOverrides.java +++ b/services/core/java/com/android/server/wm/AppCompatOverrides.java @@ -29,7 +29,7 @@ public class AppCompatOverrides { @NonNull private final AppCompatOrientationOverrides mOrientationOverrides; @NonNull - private final AppCompatCameraOverrides mAppCompatCameraOverrides; + private final AppCompatCameraOverrides mCameraOverrides; @NonNull private final AppCompatAspectRatioOverrides mAspectRatioOverrides; @NonNull @@ -46,10 +46,10 @@ public class AppCompatOverrides { @NonNull AppCompatConfiguration appCompatConfiguration, @NonNull OptPropFactory optPropBuilder, @NonNull AppCompatDeviceStateQuery appCompatDeviceStateQuery) { - mAppCompatCameraOverrides = new AppCompatCameraOverrides(activityRecord, + mCameraOverrides = new AppCompatCameraOverrides(activityRecord, appCompatConfiguration, optPropBuilder); mOrientationOverrides = new AppCompatOrientationOverrides(activityRecord, - appCompatConfiguration, optPropBuilder, mAppCompatCameraOverrides); + appCompatConfiguration, optPropBuilder, mCameraOverrides); mReachabilityOverrides = new AppCompatReachabilityOverrides(activityRecord, appCompatConfiguration, appCompatDeviceStateQuery); mAspectRatioOverrides = new AppCompatAspectRatioOverrides(activityRecord, @@ -69,8 +69,8 @@ public class AppCompatOverrides { } @NonNull - AppCompatCameraOverrides getAppCompatCameraOverrides() { - return mAppCompatCameraOverrides; + AppCompatCameraOverrides getCameraOverrides() { + return mCameraOverrides; } @NonNull diff --git a/services/core/java/com/android/server/wm/AppCompatUtils.java b/services/core/java/com/android/server/wm/AppCompatUtils.java index 1ab0868b37d1..67f5b9b03bb7 100644 --- a/services/core/java/com/android/server/wm/AppCompatUtils.java +++ b/services/core/java/com/android/server/wm/AppCompatUtils.java @@ -150,10 +150,12 @@ final class AppCompatUtils { appCompatTaskInfo.setTopActivityInSizeCompat(top.fillsParent()); } // Whether the direct top activity is eligible for letterbox education. - appCompatTaskInfo.setEligibleForLetterboxEducation( - isTopActivityResumed && top.isEligibleForLetterboxEducation()); - appCompatTaskInfo.setLetterboxEducationEnabled(top.mAppCompatController - .getAppCompatLetterboxOverrides().isLetterboxEducationEnabled()); + appCompatTaskInfo.setEligibleForLetterboxEducation(isTopActivityResumed + && top.mAppCompatController.getAppCompatLetterboxPolicy() + .isEligibleForLetterboxEducation()); + appCompatTaskInfo.setLetterboxEducationEnabled( + top.mAppCompatController.getAppCompatLetterboxOverrides() + .isLetterboxEducationEnabled()); final AppCompatAspectRatioOverrides aspectRatioOverrides = top.mAppCompatController.getAspectRatioOverrides(); diff --git a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java index f5bc9f0f9a47..230cd336d7c4 100644 --- a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java +++ b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java @@ -221,7 +221,7 @@ final class CameraCompatFreeformPolicy implements CameraStateMonitor.CameraCompa } boolean isCameraRunningAndWindowingModeEligible(@NonNull ActivityRecord activity) { - return activity.mAppCompatController.getAppCompatCameraOverrides() + return activity.mAppCompatController.getCameraOverrides() .shouldApplyFreeformTreatmentForCameraCompat() && activity.inFreeformWindowingMode() && mCameraStateMonitor.isCameraRunningForActivity(activity); @@ -232,7 +232,7 @@ final class CameraCompatFreeformPolicy implements CameraStateMonitor.CameraCompa // different camera compat aspect ratio set: this allows per-app camera compat override // aspect ratio to be smaller than the default. return isInFreeformCameraCompatMode(activity) && !activity.mAppCompatController - .getAppCompatCameraOverrides().isOverrideMinAspectRatioForCameraEnabled(); + .getCameraOverrides().isOverrideMinAspectRatioForCameraEnabled(); } boolean isInFreeformCameraCompatMode(@NonNull ActivityRecord activity) { @@ -307,7 +307,7 @@ final class CameraCompatFreeformPolicy implements CameraStateMonitor.CameraCompa boolean isTreatmentEnabledForActivity(@NonNull ActivityRecord activity, boolean checkOrientation) { int orientation = activity.getRequestedConfigurationOrientation(); - return activity.mAppCompatController.getAppCompatCameraOverrides() + return activity.mAppCompatController.getCameraOverrides() .shouldApplyFreeformTreatmentForCameraCompat() && mCameraStateMonitor.isCameraRunningForActivity(activity) && (!checkOrientation || orientation != ORIENTATION_UNDEFINED) @@ -333,6 +333,6 @@ final class CameraCompatFreeformPolicy implements CameraStateMonitor.CameraCompa || !mCameraStateMonitor.isCameraWithIdRunningForActivity(topActivity, cameraId)) { return false; } - return topActivity.mAppCompatController.getAppCompatCameraOverrides().isRefreshRequested(); + return topActivity.mAppCompatController.getCameraOverrides().isRefreshRequested(); } } diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java index 3c199dba565b..dceacc36c97e 100644 --- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java @@ -253,10 +253,10 @@ final class DisplayRotationCompatPolicy implements CameraStateMonitor.CameraComp != lastReportedConfig.windowConfiguration.getDisplayRotation()); return isTreatmentEnabledForDisplay() && isTreatmentEnabledForActivity(activity) - && activity.mAppCompatController.getAppCompatCameraOverrides() + && activity.mAppCompatController.getCameraOverrides() .shouldRefreshActivityForCameraCompat() && (displayRotationChanged - || activity.mAppCompatController.getAppCompatCameraOverrides() + || activity.mAppCompatController.getCameraOverrides() .isCameraCompatSplitScreenAspectRatioAllowed()); } @@ -281,7 +281,7 @@ final class DisplayRotationCompatPolicy implements CameraStateMonitor.CameraComp boolean isActivityEligibleForOrientationOverride(@NonNull ActivityRecord activity) { return isTreatmentEnabledForDisplay() && isCameraRunningAndWindowingModeEligible(activity, /* mustBeFullscreen */ true) - && activity.mAppCompatController.getAppCompatCameraOverrides() + && activity.mAppCompatController.getCameraOverrides() .shouldForceRotateForCameraCompat(); } @@ -325,7 +325,7 @@ final class DisplayRotationCompatPolicy implements CameraStateMonitor.CameraComp // handle dynamic changes so we shouldn't force rotate them. && activity.getOverrideOrientation() != SCREEN_ORIENTATION_NOSENSOR && activity.getOverrideOrientation() != SCREEN_ORIENTATION_LOCKED - && activity.mAppCompatController.getAppCompatCameraOverrides() + && activity.mAppCompatController.getCameraOverrides() .shouldForceRotateForCameraCompat(); } @@ -457,14 +457,14 @@ final class DisplayRotationCompatPolicy implements CameraStateMonitor.CameraComp private boolean shouldRecomputeConfigurationForCameraCompat( @NonNull ActivityRecord activityRecord) { final AppCompatCameraOverrides overrides = activityRecord.mAppCompatController - .getAppCompatCameraOverrides(); + .getCameraOverrides(); return overrides.isOverrideOrientationOnlyForCameraEnabled() || overrides.isCameraCompatSplitScreenAspectRatioAllowed() || shouldOverrideMinAspectRatio(activityRecord); } private boolean shouldOverrideMinAspectRatio(@NonNull ActivityRecord activityRecord) { - return activityRecord.mAppCompatController.getAppCompatCameraOverrides() + return activityRecord.mAppCompatController.getCameraOverrides() .isOverrideMinAspectRatioForCameraEnabled() && isCameraRunningAndWindowingModeEligible(activityRecord, /* mustBeFullscreen= */ true); diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index c6a16795dd8c..aaae160084a9 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -842,7 +842,6 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr return; } validateAndGetState(organizer); - Slog.w(TAG, "onTaskFragmentError ", exception); addPendingEvent(new PendingTaskFragmentEvent.Builder( PendingTaskFragmentEvent.EVENT_ERROR, organizer) .setErrorCallbackToken(errorCallbackToken) diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 75cefdff2b0b..37cc0d22c063 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -1626,6 +1626,11 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { for (int i = 0; i < mConfigAtEndActivities.size(); ++i) { final ActivityRecord target = mConfigAtEndActivities.get(i); final SurfaceControl targetLeash = target.getSurfaceControl(); + if (targetLeash == null) { + // activity may have been removed. In this case, no need to sync, just update state. + target.resumeConfigurationDispatch(); + continue; + } if (target.getSyncGroup() == null || target.getSyncGroup().isIgnoring(target)) { if (syncId < 0) { final BLASTSyncEngine.SyncGroup sg = mSyncEngine.prepareSyncSet( diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 3c3a180f4da1..ad19b9a44670 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -1380,7 +1380,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub break; } case HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER: { - if (!com.android.wm.shell.Flags.enableShellTopTaskTracking()) { + if (!com.android.wm.shell.Flags.enableRecentsBookendTransition()) { // Only allow restoring transient order when finishing a transition if (!chain.isFinishing()) break; } @@ -1416,7 +1416,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final TaskDisplayArea taskDisplayArea = thisTask.getTaskDisplayArea(); taskDisplayArea.moveRootTaskBehindRootTask(thisTask.getRootTask(), restoreAt); - if (com.android.wm.shell.Flags.enableShellTopTaskTracking()) { + if (com.android.wm.shell.Flags.enableRecentsBookendTransition()) { // Because we are in a transient launch transition, the requested visibility of // tasks does not actually change for the transient-hide tasks, but we do want // the restoration of these transient-hide tasks to top to be a part of this diff --git a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java index 148c96850d34..263ada8b36f6 100644 --- a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java @@ -69,6 +69,7 @@ import android.os.Binder; import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; +import android.platform.test.annotations.EnableFlags; import android.service.quicksettings.TileService; import android.testing.TestableContext; @@ -79,6 +80,7 @@ import com.android.internal.statusbar.IStatusBar; import com.android.server.LocalServices; import com.android.server.policy.GlobalActionsProvider; import com.android.server.wm.ActivityTaskManagerInternal; +import com.android.systemui.shared.Flags; import libcore.junit.util.compat.CoreCompatChangeRule; @@ -105,6 +107,7 @@ public class StatusBarManagerServiceTest { TEST_SERVICE); private static final CharSequence APP_NAME = "AppName"; private static final CharSequence TILE_LABEL = "Tile label"; + private static final int SECONDARY_DISPLAY_ID = 2; @Rule public final TestableContext mContext = @@ -749,6 +752,29 @@ public class StatusBarManagerServiceTest { } @Test + @EnableFlags(Flags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS) + public void testDisableForAllDisplays() throws Exception { + int user1Id = 0; + mockUidCheck(); + mockCurrentUserCheck(user1Id); + + mStatusBarManagerService.onDisplayAdded(SECONDARY_DISPLAY_ID); + + int expectedFlags = DISABLE_MASK & DISABLE_BACK; + String pkg = mContext.getPackageName(); + + // before disabling + assertEquals(DISABLE_NONE, + mStatusBarManagerService.getDisableFlags(mMockStatusBar, user1Id)[0]); + + // disable + mStatusBarManagerService.disable(expectedFlags, mMockStatusBar, pkg); + + verify(mMockStatusBar).disable(0, expectedFlags, 0); + verify(mMockStatusBar).disable(SECONDARY_DISPLAY_ID, expectedFlags, 0); + } + + @Test public void testSetHomeDisabled() throws Exception { int expectedFlags = DISABLE_MASK & DISABLE_HOME; String pkg = mContext.getPackageName(); @@ -851,6 +877,29 @@ public class StatusBarManagerServiceTest { } @Test + @EnableFlags(Flags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS) + public void testDisable2ForAllDisplays() throws Exception { + int user1Id = 0; + mockUidCheck(); + mockCurrentUserCheck(user1Id); + + mStatusBarManagerService.onDisplayAdded(SECONDARY_DISPLAY_ID); + + int expectedFlags = DISABLE2_MASK & DISABLE2_NOTIFICATION_SHADE; + String pkg = mContext.getPackageName(); + + // before disabling + assertEquals(DISABLE_NONE, + mStatusBarManagerService.getDisableFlags(mMockStatusBar, user1Id)[0]); + + // disable + mStatusBarManagerService.disable2(expectedFlags, mMockStatusBar, pkg); + + verify(mMockStatusBar).disable(0, 0, expectedFlags); + verify(mMockStatusBar).disable(SECONDARY_DISPLAY_ID, 0, expectedFlags); + } + + @Test public void testSetQuickSettingsDisabled2() throws Exception { int expectedFlags = DISABLE2_MASK & DISABLE2_QUICK_SETTINGS; String pkg = mContext.getPackageName(); @@ -1092,6 +1141,7 @@ public class StatusBarManagerServiceTest { // disable mStatusBarManagerService.disableForUser(expectedUser1Flags, mMockStatusBar, pkg, user1Id); mStatusBarManagerService.disableForUser(expectedUser2Flags, mMockStatusBar, pkg, user2Id); + // check that right flag is disabled assertEquals(expectedUser1Flags, mStatusBarManagerService.getDisableFlags(mMockStatusBar, user1Id)[0]); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java index d2f8d14c5007..d1afa38cf3f6 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java @@ -17,6 +17,7 @@ package com.android.server.notification; import static android.os.UserHandle.USER_ALL; import static android.service.notification.Adjustment.KEY_IMPORTANCE; +import static android.service.notification.Adjustment.KEY_TYPE; import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION; import static android.service.notification.Adjustment.TYPE_NEWS; import static android.service.notification.Adjustment.TYPE_PROMOTION; @@ -165,6 +166,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase { mContext.getOrCreateTestableResources().addOverride( com.android.internal.R.string.config_defaultAssistantAccessComponent, mCn.flattenToString()); + mNm.mDefaultUnsupportedAdjustments = new String[] {}; mAssistants = spy(mNm.new NotificationAssistants(mContext, mLock, mUserProfiles, miPm)); when(mNm.getBinderService()).thenReturn(mINm); mContext.ensureTestableResources(); @@ -660,7 +662,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase { mAssistants.disallowAdjustmentType(Adjustment.KEY_RANKING_SCORE); assertThat(mAssistants.getAllowedAssistantAdjustments()) .doesNotContain(Adjustment.KEY_RANKING_SCORE); - assertThat(mAssistants.getAllowedAssistantAdjustments()).contains(Adjustment.KEY_TYPE); + assertThat(mAssistants.getAllowedAssistantAdjustments()).contains(KEY_TYPE); } @Test @@ -856,7 +858,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase { mAssistants.new ManagedServiceInfo(null, mCn, userId, false, null, 35, 2345256); // Ensure bundling is enabled - mAssistants.setAdjustmentTypeSupportedState(info, Adjustment.KEY_TYPE, true); + mAssistants.setAdjustmentTypeSupportedState(info, KEY_TYPE, true); // Enable these specific bundle types mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_PROMOTION, false); mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, true); @@ -890,7 +892,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase { .isEqualTo(NotificationProtoEnums.TYPE_CONTENT_RECOMMENDATION); // Disable the top-level bundling setting - mAssistants.setAdjustmentTypeSupportedState(info, Adjustment.KEY_TYPE, false); + mAssistants.setAdjustmentTypeSupportedState(info, KEY_TYPE, false); // Enable these specific bundle types mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_PROMOTION, true); mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, false); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 85c592084acf..43302264964e 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -790,6 +790,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { TestableResources tr = mContext.getOrCreateTestableResources(); tr.addOverride(com.android.internal.R.string.config_defaultSearchSelectorPackageName, SEARCH_SELECTOR_PKG); + tr.addOverride(R.array.config_notificationDefaultUnsupportedAdjustments, + new String[] {KEY_TYPE}); doAnswer(invocation -> { mOnPermissionChangeListener = invocation.getArgument(2); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRefresherTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRefresherTests.java index 63dafcd0b5a8..c667d76f36ab 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRefresherTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRefresherTests.java @@ -103,7 +103,7 @@ public class ActivityRefresherTests extends WindowTestsBase { @Test public void testShouldRefreshActivity_refreshDisabledForActivity() throws Exception { configureActivityAndDisplay(); - when(mActivity.mAppCompatController.getAppCompatCameraOverrides() + when(mActivity.mAppCompatController.getCameraOverrides() .shouldRefreshActivityForCameraCompat()).thenReturn(false); mActivityRefresher.addEvaluator(mEvaluatorTrue); @@ -161,7 +161,7 @@ public class ActivityRefresherTests extends WindowTestsBase { configureActivityAndDisplay(); mActivityRefresher.addEvaluator(mEvaluatorTrue); doReturn(true) - .when(mActivity.mAppCompatController.getAppCompatCameraOverrides()) + .when(mActivity.mAppCompatController.getCameraOverrides()) .shouldRefreshActivityViaPauseForCameraCompat(); mActivityRefresher.onActivityConfigurationChanging(mActivity, mNewConfig, mOldConfig); @@ -174,7 +174,7 @@ public class ActivityRefresherTests extends WindowTestsBase { configureActivityAndDisplay(); mActivityRefresher.addEvaluator(mEvaluatorTrue); doReturn(true) - .when(mActivity.mAppCompatController.getAppCompatCameraOverrides()) + .when(mActivity.mAppCompatController.getCameraOverrides()) .shouldRefreshActivityViaPauseForCameraCompat(); mActivityRefresher.onActivityRefreshed(mActivity); @@ -188,7 +188,7 @@ public class ActivityRefresherTests extends WindowTestsBase { private void assertActivityRefreshRequested(boolean refreshRequested, boolean cycleThroughStop) throws Exception { - verify(mActivity.mAppCompatController.getAppCompatCameraOverrides(), + verify(mActivity.mAppCompatController.getCameraOverrides(), times(refreshRequested ? 1 : 0)).setIsRefreshRequested(true); final RefreshCallbackItem refreshCallbackItem = @@ -212,9 +212,9 @@ public class ActivityRefresherTests extends WindowTestsBase { .build() .getTopMostActivity(); - spyOn(mActivity.mAppCompatController.getAppCompatCameraOverrides()); + spyOn(mActivity.mAppCompatController.getCameraOverrides()); doReturn(true).when(mActivity).inFreeformWindowingMode(); doReturn(true).when(mActivity.mAppCompatController - .getAppCompatCameraOverrides()).shouldRefreshActivityForCameraCompat(); + .getCameraOverrides()).shouldRefreshActivityForCameraCompat(); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java index 1d138e4a48d9..4ad1cd192eb6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java @@ -393,7 +393,7 @@ public class AppCompatCameraOverridesTest extends WindowTestsBase { } private AppCompatCameraOverrides getAppCompatCameraOverrides() { - return activity().top().mAppCompatController.getAppCompatCameraOverrides(); + return activity().top().mAppCompatController.getCameraOverrides(); } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java index 576d17af2e79..716f86418bcb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java @@ -401,7 +401,7 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase { throws Exception { configureActivity(SCREEN_ORIENTATION_PORTRAIT); - doReturn(false).when(mActivity.mAppCompatController.getAppCompatCameraOverrides()) + doReturn(false).when(mActivity.mAppCompatController.getCameraOverrides()) .shouldRefreshActivityForCameraCompat(); mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1); @@ -431,7 +431,7 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase { public void testOnActivityConfigurationChanging_cycleThroughStopDisabledForApp() throws Exception { configureActivity(SCREEN_ORIENTATION_PORTRAIT); - doReturn(true).when(mActivity.mAppCompatController.getAppCompatCameraOverrides()) + doReturn(true).when(mActivity.mAppCompatController.getCameraOverrides()) .shouldRefreshActivityViaPauseForCameraCompat(); mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1); @@ -477,7 +477,7 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase { configureActivity(SCREEN_ORIENTATION_PORTRAIT); final float configAspectRatio = 1.5f; mWm.mAppCompatConfiguration.setCameraCompatAspectRatio(configAspectRatio); - doReturn(true).when(mActivity.mAppCompatController.getAppCompatCameraOverrides()) + doReturn(true).when(mActivity.mAppCompatController.getCameraOverrides()) .isOverrideMinAspectRatioForCameraEnabled(); mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1); @@ -608,7 +608,7 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase { .build(); mActivity.mAppCompatController.getSizeCompatModePolicy().clearSizeCompatMode(); - spyOn(mActivity.mAppCompatController.getAppCompatCameraOverrides()); + spyOn(mActivity.mAppCompatController.getCameraOverrides()); spyOn(mActivity.info); doReturn(mActivity).when(mDisplayContent).topRunningActivity(anyBoolean()); @@ -630,7 +630,7 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase { private void assertActivityRefreshRequested(boolean refreshRequested, boolean cycleThroughStop) throws Exception { - verify(mActivity.mAppCompatController.getAppCompatCameraOverrides(), + verify(mActivity.mAppCompatController.getCameraOverrides(), times(refreshRequested ? 1 : 0)).setIsRefreshRequested(true); final RefreshCallbackItem refreshCallbackItem = diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java index 23c767c87e4f..02b796f5440f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java @@ -267,7 +267,7 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase { public void testTreatmentDisabledPerApp_noForceRotationOrRefresh() throws Exception { configureActivity(SCREEN_ORIENTATION_PORTRAIT); - doReturn(false).when(mActivity.mAppCompatController.getAppCompatCameraOverrides()) + doReturn(false).when(mActivity.mAppCompatController.getCameraOverrides()) .shouldForceRotateForCameraCompat(); mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1); @@ -469,7 +469,7 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase { throws Exception { configureActivity(SCREEN_ORIENTATION_PORTRAIT); - doReturn(false).when(mActivity.mAppCompatController.getAppCompatCameraOverrides()) + doReturn(false).when(mActivity.mAppCompatController.getCameraOverrides()) .shouldRefreshActivityForCameraCompat(); mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1); @@ -496,7 +496,7 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase { throws Exception { configureActivity(SCREEN_ORIENTATION_PORTRAIT); doReturn(false).when(mActivity - .mAppCompatController.getAppCompatCameraOverrides()) + .mAppCompatController.getCameraOverrides()) .isCameraCompatSplitScreenAspectRatioAllowed(); mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1); @@ -509,7 +509,7 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase { public void testOnActivityConfigurationChanging_splitScreenAspectRatioAllowed_refresh() throws Exception { configureActivity(SCREEN_ORIENTATION_PORTRAIT); - doReturn(true).when(mActivity.mAppCompatController.getAppCompatCameraOverrides()) + doReturn(true).when(mActivity.mAppCompatController.getCameraOverrides()) .isCameraCompatSplitScreenAspectRatioAllowed(); mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1); @@ -535,7 +535,7 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase { public void testOnActivityConfigurationChanging_cycleThroughStopDisabledForApp() throws Exception { configureActivity(SCREEN_ORIENTATION_PORTRAIT); - doReturn(true).when(mActivity.mAppCompatController.getAppCompatCameraOverrides()) + doReturn(true).when(mActivity.mAppCompatController.getCameraOverrides()) .shouldRefreshActivityViaPauseForCameraCompat(); mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1); @@ -599,7 +599,7 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase { ActivityInfo.UNIVERSAL_RESIZABLE_BY_DEFAULT); spyOn(mActivity.mAtmService.getLifecycleManager()); - spyOn(mActivity.mAppCompatController.getAppCompatCameraOverrides()); + spyOn(mActivity.mAppCompatController.getCameraOverrides()); doReturn(mActivity).when(mDisplayContent).topRunningActivity(anyBoolean()); doReturn(naturalOrientation).when(mDisplayContent).getNaturalOrientation(); @@ -611,7 +611,7 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase { private void assertActivityRefreshRequested(boolean refreshRequested, boolean cycleThroughStop) throws Exception { - verify(mActivity.mAppCompatController.getAppCompatCameraOverrides(), + verify(mActivity.mAppCompatController.getCameraOverrides(), times(refreshRequested ? 1 : 0)).setIsRefreshRequested(true); final RefreshCallbackItem refreshCallbackItem = diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index a84b374f9487..2630565f2785 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -4683,7 +4683,8 @@ public class SizeCompatTests extends WindowTestsBase { prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); - assertFalse(mActivity.isEligibleForLetterboxEducation()); + assertFalse(mActivity.mAppCompatController.getAppCompatLetterboxPolicy() + .isEligibleForLetterboxEducation()); } @Test @@ -4694,7 +4695,8 @@ public class SizeCompatTests extends WindowTestsBase { prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); - assertFalse(mActivity.isEligibleForLetterboxEducation()); + assertFalse(mActivity.mAppCompatController.getAppCompatLetterboxPolicy() + .isEligibleForLetterboxEducation()); } @Test @@ -4716,7 +4718,8 @@ public class SizeCompatTests extends WindowTestsBase { false /*moveParents*/, "test"); organizer.mPrimary.setBounds(0, 0, 1000, 600); - assertFalse(mActivity.isEligibleForLetterboxEducation()); + assertFalse(mActivity.mAppCompatController.getAppCompatLetterboxPolicy() + .isEligibleForLetterboxEducation()); assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode()); } @@ -4728,7 +4731,8 @@ public class SizeCompatTests extends WindowTestsBase { prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); - assertFalse(mActivity.isEligibleForLetterboxEducation()); + assertFalse(mActivity.mAppCompatController.getAppCompatLetterboxPolicy() + .isEligibleForLetterboxEducation()); assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy() .isLetterboxedForFixedOrientationAndAspectRatio()); } @@ -4745,14 +4749,16 @@ public class SizeCompatTests extends WindowTestsBase { createWindowState(new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING), mActivity)); - assertFalse(mActivity.isEligibleForLetterboxEducation()); + assertFalse(mActivity.mAppCompatController.getAppCompatLetterboxPolicy() + .isEligibleForLetterboxEducation()); // Verify that after removing the starting window isEligibleForLetterboxEducation returns // true and mTask.dispatchTaskInfoChangedIfNeeded is called. spyOn(mTask); mActivity.removeStartingWindow(); - assertTrue(mActivity.isEligibleForLetterboxEducation()); + assertTrue(mActivity.mAppCompatController.getAppCompatLetterboxPolicy() + .isEligibleForLetterboxEducation()); verify(mTask).dispatchTaskInfoChangedIfNeeded(true); } @@ -4768,14 +4774,16 @@ public class SizeCompatTests extends WindowTestsBase { createWindowState(new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING), mActivity)); - assertFalse(mActivity.isEligibleForLetterboxEducation()); + assertFalse(mActivity.mAppCompatController.getAppCompatLetterboxPolicy() + .isEligibleForLetterboxEducation()); // Verify that after removing the starting window isEligibleForLetterboxEducation still // returns false and mTask.dispatchTaskInfoChangedIfNeeded isn't called. spyOn(mTask); mActivity.removeStartingWindow(); - assertFalse(mActivity.isEligibleForLetterboxEducation()); + assertFalse(mActivity.mAppCompatController.getAppCompatLetterboxPolicy() + .isEligibleForLetterboxEducation()); verify(mTask, never()).dispatchTaskInfoChangedIfNeeded(true); } @@ -4787,7 +4795,8 @@ public class SizeCompatTests extends WindowTestsBase { prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); - assertTrue(mActivity.isEligibleForLetterboxEducation()); + assertTrue(mActivity.mAppCompatController.getAppCompatLetterboxPolicy() + .isEligibleForLetterboxEducation()); assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy() .isLetterboxedForFixedOrientationAndAspectRatio()); } @@ -4802,7 +4811,8 @@ public class SizeCompatTests extends WindowTestsBase { rotateDisplay(mActivity.mDisplayContent, ROTATION_90); - assertTrue(mActivity.isEligibleForLetterboxEducation()); + assertTrue(mActivity.mAppCompatController.getAppCompatLetterboxPolicy() + .isEligibleForLetterboxEducation()); assertFalse(mActivity.mAppCompatController.getAspectRatioPolicy() .isLetterboxedForFixedOrientationAndAspectRatio()); assertTrue(mActivity.inSizeCompatMode()); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 24fb8c5da2d7..da4165553e57 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -180,7 +180,7 @@ import java.util.stream.IntStream; * permission-protected. Your application cannot access the protected * information unless it has the appropriate permissions declared in * its manifest file. Where permissions apply, they are noted in the - * the methods through which you access the protected information. + * methods through which you access the protected information. * * <p>TelephonyManager is intended for use on devices that implement * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY FEATURE_TELEPHONY}. On devices @@ -633,11 +633,14 @@ public class TelephonyManager { } /** - * Returns the multi SIM variant - * Returns DSDS for Dual SIM Dual Standby - * Returns DSDA for Dual SIM Dual Active - * Returns TSTS for Triple SIM Triple Standby - * Returns UNKNOWN for others + * Returns the multi SIM variant. + * + * <ul> + * <li>Returns DSDS for Dual SIM Dual Standby.</li> + * <li>Returns DSDA for Dual SIM Dual Active.</li> + * <li>Returns TSTS for Triple SIM Triple Standby.</li> + * <li>Returns UNKNOWN for others.</li> + * </ul> */ /** {@hide} */ @UnsupportedAppUsage @@ -657,10 +660,14 @@ public class TelephonyManager { /** * Returns the number of phones available. - * Returns 0 if none of voice, sms, data is not supported - * Returns 1 for Single standby mode (Single SIM functionality). - * Returns 2 for Dual standby mode (Dual SIM functionality). - * Returns 3 for Tri standby mode (Tri SIM functionality). + * + * <ul> + * <li>Returns 0 if none of voice, sms, data is supported.</li> + * <li>Returns 1 for Single standby mode (Single SIM functionality).</li> + * <li>Returns 2 for Dual standby mode (Dual SIM functionality).</li> + * <li>Returns 3 for Tri standby mode (Tri SIM functionality).</li> + * </ul> + * * @deprecated Use {@link #getActiveModemCount} instead. */ @Deprecated @@ -671,10 +678,12 @@ public class TelephonyManager { /** * Returns the number of logical modems currently configured to be activated. * - * Returns 0 if none of voice, sms, data is not supported - * Returns 1 for Single standby mode (Single SIM functionality). - * Returns 2 for Dual standby mode (Dual SIM functionality). - * Returns 3 for Tri standby mode (Tri SIM functionality). + * <ul> + * <li>Returns 0 if none of voice, sms, data is supported.</li> + * <li>Returns 1 for Single standby mode (Single SIM functionality).</li> + * <li>Returns 2 for Dual standby mode (Dual SIM functionality).</li> + * <li>Returns 3 for Tri standby mode (Tri SIM functionality).</li> + * </ul> */ public int getActiveModemCount() { int modemCount = 1; |