Merge "Send RR event changed when frame rate is overridden" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 2ce3221..302168d8 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -1856,6 +1856,41 @@
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 4a78d017..8fa2362 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -273,4 +273,7 @@
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 e5d80de..05b3316 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -665,8 +665,10 @@
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 @@
/** 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 @@
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 edd17e8..914ca73 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -295,6 +295,16 @@
}
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 2f16115..ceafce2 100644
--- a/core/java/android/companion/AssociationInfo.java
+++ b/core/java/android/companion/AssociationInfo.java
@@ -287,8 +287,8 @@
/**
* 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 @@
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 @@
&& 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 @@
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 @@
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 32cbf32..a098a60 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -385,6 +385,10 @@
public void setAssociatedDevice(AssociatedDevice associatedDevice) {
mAssociatedDevice = associatedDevice;
}
+ /** @hide */
+ public void setDeviceIcon(Icon deviceIcon) {
+ mDeviceIcon = deviceIcon;
+ }
/** @hide */
@NonNull
@@ -492,9 +496,10 @@
/**
* 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 a96ba11..566e78a 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -23,7 +23,6 @@
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.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 @@
@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 @@
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 @@
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 @@
}
}
- 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.");
}
+
+ Bitmap bitmap;
Drawable drawable = icon.loadDrawable(context);
- float density = context.getResources().getDisplayMetrics().density;
-
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 875b909..4aa7462 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -2831,11 +2831,9 @@
}
}
- 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 @@
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 @@
private void freeBuffer() {
mFlags = 0;
- resetSquashingState();
+ resetSqaushingState();
if (mOwnsNativeParcelObject) {
nativeFreeBuffer(mNativePtr);
}
@@ -5517,7 +5513,7 @@
}
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 73d1e17..a22333b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9314,6 +9314,16 @@
"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 a558622..792e6ff 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -43,7 +43,7 @@
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 01de5435..e1dc6f6 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
@@ -131,7 +131,7 @@
== 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 0000000..19ae608
--- /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 fb4a19b..eb50fc2 100644
--- a/core/java/android/timezone/TelephonyNetworkFinder.java
+++ b/core/java/android/timezone/TelephonyNetworkFinder.java
@@ -19,7 +19,6 @@
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 @@
*/
@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 d88b6d6..7206906 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -28365,10 +28365,8 @@
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 64e7bec..cd8a85a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2968,6 +2968,20 @@
}
}
+ /**
+ * 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 64277b1..d267c94 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -160,6 +160,9 @@
/** @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 ed6ec32..3cc0042 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 @@
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 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 158b526..928fa8c 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -265,8 +265,17 @@
*/
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 @@
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 @@
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 @@
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 5d0b340..69c812c 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -109,6 +109,7 @@
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 7327970..aad8f8a 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 18ba6a1..a201f1f 100644
--- a/core/tests/coretests/src/android/app/NotificationManagerTest.java
+++ b/core/tests/coretests/src/android/app/NotificationManagerTest.java
@@ -263,6 +263,38 @@
}
@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 4c7e477..d0d1721 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.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 @@
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 b10b099..e421026 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -134,6 +134,16 @@
}
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 90ea7d3..dd387b3 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.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 @@
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 a83327b..f1ba042 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.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 @@
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 42b66aa..896f2ee 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.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 @@
) : 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 9e58b5b..d3cfbd0 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.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.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 @@
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 @@
}
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 @@
@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 @@
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 @@
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 fbbcff2..7f65e22 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.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 @@
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 5c5dde7..a649247 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.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 @@
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 d7669ed..0974930 100644
--- a/libs/WindowManager/Shell/shared/Android.bp
+++ b/libs/WindowManager/Shell/shared/Android.bp
@@ -78,3 +78,17 @@
"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 08e3692..12dfbd9 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.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 @@
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 @@
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler,
@ShellBackgroundThread ShellExecutor bgExecutor,
+ TaskViewRepository taskViewRepository,
TaskViewTransitions taskViewTransitions,
Transitions transitions,
SyncTransactionQueue syncQueue,
@@ -347,7 +350,12 @@
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 @@
@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 @@
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 72be066..e69d60d 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.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.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 @@
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 @@
? 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 @@
}
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 @@
/**
* 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 bcd40a9..c4696d5 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 @@
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 e779879..3777907 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 @@
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 cbbe8a2..8404259 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 @@
@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 408160d..67e3453 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.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 @@
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler,
@ShellBackgroundThread ShellExecutor bgExecutor,
+ TaskViewRepository taskViewRepository,
TaskViewTransitions taskViewTransitions,
Transitions transitions,
SyncTransactionQueue syncQueue,
@@ -280,6 +282,7 @@
mainExecutor,
mainHandler,
bgExecutor,
+ taskViewRepository,
taskViewTransitions,
transitions,
syncQueue,
@@ -1028,8 +1031,9 @@
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 c8d0dab..793bdf0 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 @@
@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 9b5a289..1ce093e 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.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.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 @@
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 @@
// 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 @@
.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 9c3e815..912d383 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 @@
}
@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 63c1512..a033b824 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 @@
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 @@
mAnimationStartCallback.run();
}
if (mStartTransaction != null) {
+ onAlphaAnimationUpdate(getStartAlphaValue(), mStartTransaction);
mStartTransaction.apply();
}
}
@@ -66,6 +72,10 @@
@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 @@
@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 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 @@
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 562b260..b1984cc 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 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 @@
//
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 @@
}
@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 ed532ca..21b0820 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 @@
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 4902455..8cba076 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.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 @@
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 @@
PipTransitionState pipTransitionState,
PipDisplayLayoutState pipDisplayLayoutState,
PipUiStateChangeController pipUiStateChangeController,
+ DisplayController displayController,
Optional<DesktopUserRepositories> desktopUserRepositoriesOptional,
Optional<DesktopWallpaperActivityTokenProvider>
desktopWallpaperActivityTokenProviderOptional) {
@@ -164,6 +168,7 @@
mPipTransitionState = pipTransitionState;
mPipTransitionState.addPipTransitionStateChangedListener(this);
mPipDisplayLayoutState = pipDisplayLayoutState;
+ mDisplayController = displayController;
mDesktopUserRepositoriesOptional = desktopUserRepositoriesOptional;
mDesktopWallpaperActivityTokenProviderOptional =
desktopWallpaperActivityTokenProviderOptional;
@@ -513,7 +518,7 @@
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 @@
.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 @@
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 @@
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 36eaebd..afc6fee 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 @@
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 @@
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 @@
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 @@
&& !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 @@
// 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 @@
}
}
- if (Flags.enableShellTopTaskTracking()) {
+ if (Flags.enableRecentsBookendTransition()) {
if (!wct.isEmpty()) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
"[%d] RecentsController.finishInner: "
@@ -1574,7 +1574,7 @@
/**
* 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 c9136b4..37c9351 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.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 @@
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 361d7663..0445add 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 @@
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 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 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 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 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 0000000..59becf7
--- /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 e4fcff0c..b2813bb 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 @@
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 @@
mTaskOrganizer = taskOrganizer;
mShellExecutor = shellExecutor;
mSyncQueue = syncQueue;
- mTaskViewTransitions = null;
+ mTaskViewController = null;
}
/**
@@ -61,8 +61,8 @@
/** 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 5c7dd07..d19a7ea 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.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 @@
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 @@
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 @@
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 @@
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 @@
}
/**
- * 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 @@
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 @@
@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 @@
// 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 @@
}
/**
- * 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 @@
return;
}
- if (isUsingShellTransitions()) {
- mTaskViewTransitions.setTaskViewVisible(this, false /* visible */);
+ if (mTaskViewController.isUsingShellTransitions()) {
+ mTaskViewController.setTaskViewVisible(this, false /* visible */);
return;
}
@@ -604,15 +417,16 @@
}
}
+ 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 @@
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 @@
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 (!mSurfaceCreated) {
+ return null;
}
- if (newTask) {
- mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, true /* intercept */);
- }
+ return mTaskViewBase.getCurrentBoundsOnScreen();
+ }
- if (mTaskInfo.taskDescription != null) {
- int backgroundColor = mTaskInfo.taskDescription.getBackgroundColor();
- mTaskViewBase.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 */);
+ /** 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 0cbb7bd..6c90a90 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 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.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.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 @@
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 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 @@
// 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 @@
return mTaskViewRepo;
}
- void addTaskView(TaskViewTaskController tv) {
+ @Override
+ public void registerTaskView(TaskViewTaskController tv) {
synchronized (mRegistered) {
if (!mRegistered[0]) {
mRegistered[0] = true;
@@ -133,7 +158,8 @@
}
}
- void removeTaskView(TaskViewTaskController tv) {
+ @Override
+ public void unregisterTaskView(TaskViewTaskController tv) {
if (useRepo()) {
mTaskViewRepo.remove(tv);
} else {
@@ -142,27 +168,12 @@
// 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 @@
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 @@
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 @@
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 @@
}
}
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 @@
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 e61929f..2133275 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.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 @@
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 @@
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 @@
}
}
- 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 0d75e65..7948ead 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 @@
SurfaceControl taskSurface,
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT) {
- if (!shouldShowWindowDecor(taskInfo)) {
- return false;
- }
createWindowDecoration(taskInfo, taskSurface, startT, finishT);
return true;
}
@@ -125,12 +122,9 @@
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 @@
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 1ca82d2..3943784 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 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 @@
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 @@
@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 @@
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 eeb83df..417b43a 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.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 @@
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 04f9ada..03aad1c 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.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 @@
@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 @@
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 9cc18ff..607e6a4 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 @@
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 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 @@
@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 @@
@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 @@
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 @@
@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 @@
@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 @@
});
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 aef44a4..bd857c7 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 @@
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 66636c5..6ac34d7 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 @@
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 @@
@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 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 @@
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 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 @@
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 @@
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 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 @@
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 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 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 @@
// 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 @@
// 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 @@
// 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 @@
assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
mTaskView.removeTask();
- verify(mTaskViewTransitions, never()).closeTaskView(any(), any());
+ assertFalse(mTaskViewTransitions.hasPending());
}
@Test
@@ -628,14 +629,14 @@
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 @@
mTaskViewTaskController.onTaskAppeared(mTaskInfo, mLeash);
assertNull(mTaskViewTaskController.getTaskInfo());
- verify(mTaskViewTransitions).closeTaskView(any(), eq(mTaskViewTaskController));
+ verify(mTaskViewTransitions).removeTaskView(eq(mTaskViewTaskController), any());
}
@Test
@@ -655,7 +656,7 @@
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 @@
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 @@
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 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 @@
});
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 @@
@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 @@
@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 5f6f18f..326f11e 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 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 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 @@
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 @@
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 @@
@Test
public void testSetTaskVisibility_taskRemoved_noNPE() {
- mTaskViewTransitions.removeTaskView(mTaskViewTaskController);
+ mTaskViewTransitions.unregisterTaskView(mTaskViewTaskController);
assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
@@ -221,7 +233,7 @@
@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 0000000..ec9ee22
--- /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 0000000..0488cba
--- /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 fd8cecb..267c9f6 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 601e001..0027d63 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 @@
((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 3f671b9..77e2cc7 100644
--- a/packages/SettingsLib/BannerMessagePreference/Android.bp
+++ b/packages/SettingsLib/BannerMessagePreference/Android.bp
@@ -14,12 +14,16 @@
"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 0000000..d113b547
--- /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 0000000..cb89d9a
--- /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 0000000..f820c35
--- /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 0000000..8037a8b
--- /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 072eb58..3f806e1 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 0000000..a677a66
--- /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 9d53e39..ca596d8 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" />
+ <RelativeLayout
+ android:id="@+id/top_row"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="8dp"
+ android:orientation="horizontal">
- <ImageButton
- android:id="@+id/banner_dismiss_btn"
+ <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"
+ 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_title"
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>
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
+ android:paddingTop="0dp"
+ android:paddingBottom="4dp"
+ android:textAppearance="@style/Banner.Title.SettingsLib"/>
- <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"/>
-
- <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"/>
-
- <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">
-
- <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 0000000..b10ef6e
--- /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 0000000..c74e391
--- /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 fede44f..5909f8e 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 0000000..b864311
--- /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 96634a5..86d5f47 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 53d72d1..891def1 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 10769ec..60a9ebd 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.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.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 @@
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 @ColorRes int getBackgroundColorResId() {
return mBackgroundColorResId;
}
+
+ public @ColorRes int getButtonBackgroundColorResId() {
+ return mButtonBackgroundColorResId;
+ }
}
private static final String TAG = "BannerPreference";
@@ -95,6 +117,8 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
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 0000000..7545563
--- /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 08dd27f..a377f31 100644
--- a/packages/SettingsLib/ButtonPreference/Android.bp
+++ b/packages/SettingsLib/ButtonPreference/Android.bp
@@ -14,12 +14,15 @@
"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 0000000..0972b62
--- /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 0000000..9bf5c43
--- /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 0000000..b993811
--- /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 0000000..fa13b41
--- /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 0000000..e7fb572
--- /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 3963732..5208e20 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 0000000..a1772d5
--- /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 0000000..b374dea
--- /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 8e85046..be705b5 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 @@
}
/** 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 @@
* [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 @@
context,
callingPid,
callingUid,
- this as PreferenceMetadata,
+ this,
)
/** Returns the required permissions to write preference value. */
@@ -136,7 +136,7 @@
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 623ea22..fecf3e5 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 @@
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 @@
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 b82c554..65fbe2b 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 @@
}
/** 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 @@
}
/** 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 @@
}
/** 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 1661dfb..e5c009d 100644
--- a/packages/SettingsLib/SettingsTheme/Android.bp
+++ b/packages/SettingsLib/SettingsTheme/Android.bp
@@ -16,6 +16,7 @@
],
resource_dirs: ["res"],
static_libs: [
+ "aconfig_settingstheme_exported_flags_java_lib",
"androidx.preference_preference",
"com.google.android.material_material",
],
@@ -23,12 +24,12 @@
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 0000000..83e732b
--- /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
similarity index 100%
rename from packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_chevron.xml
rename to 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
similarity index 100%
rename from packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_collapse.xml
rename to 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 0000000..3ba85a2
--- /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
similarity index 100%
rename from packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_expand.xml
rename to 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 0000000..aa4155b
--- /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 0000000..9caa095
--- /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 0000000..cdcb982
--- /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 0000000..448d596
--- /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 0000000..c387305
--- /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 511e2bb..4ef747a 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 e57fe4f..d677bba 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 c5c613b..e8ab99e 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 6794cd0..1776d25 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 @@
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 @@
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 b2ed268..5790fde 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 cf695d0..5e72c43 100644
--- a/packages/SettingsLib/Spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/build.gradle.kts
@@ -28,7 +28,7 @@
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 04ef96a..4113ad8 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 a0bbb0c..1396629 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/spa/build.gradle.kts
@@ -52,14 +52,14 @@
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 bdbe62c..8e59fd7 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.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 @@
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 7dbd320..03cd243 100644
--- a/packages/SettingsLib/Spa/testutils/build.gradle.kts
+++ b/packages/SettingsLib/Spa/testutils/build.gradle.kts
@@ -36,7 +36,7 @@
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 3c3de04..502eb6c 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 6cf9e83..3da2271 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 b7108c9..cf52eb3 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 @@
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 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 @@
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 7b4a2ca..d367748 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 @@
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 6681c014..242bdce 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 @@
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 1c6d681..9505977 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 @@
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 9531bc3..1a7ae72 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -176,13 +176,6 @@
}
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 @@
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 a1117e1..431a376 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 @@
/** 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 59b4a09..c61bb6e 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.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 @@
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 73efea7..2713bb0 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 @@
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 4ef9792..0df1073 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 @@
}
@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 aa71b84..75c1742 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.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 @@
DragAndDropController dragAndDropController,
ShellExecutor shellMainExecutor,
Handler shellMainHandler,
+ TaskViewRepository taskViewRepository,
TaskViewTransitions taskViewTransitions,
Transitions transitions,
SyncTransactionQueue syncQueue,
@@ -86,7 +88,7 @@
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 2ed0671..3911c19 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.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 @@
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 2705cda..39703ab 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.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 @@
@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 @@
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 cf9ee61..826329d 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_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 @@
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 0000000..cb0d674
--- /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 7508838..fab7922 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 @@
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 @@
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 @@
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 @@
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 3ec3e3c..27223d8b 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 001943c..9c46a16 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 cc704b2..9859475 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 @@
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 55e853e..ae9276f 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 @@
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 @@
"--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 @@
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 261ef59c..a08d1d6 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 @@
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 @@
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 @@
}
}
- 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 @@
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 567a69e..70e7d46 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 @@
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 5e5ca62..b009b09 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 103e152..ad41342 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 3415deb..674937d 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 @@
@HostSideTestKeep
@HostSideTestClassLoadHook(
"com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded")
-public class TinyFrameworkAnnotations {
+public final class TinyFrameworkAnnotations {
@HostSideTestKeep
public TinyFrameworkAnnotations() {
}
@@ -42,7 +42,7 @@
public int remove;
@HostSideTestKeep
- public int addOne(int value) {
+ public final int addOne(int value) {
return value + 1;
}
@@ -61,10 +61,10 @@
}
@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 0cbbf6d..2c106d3 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 @@
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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 0e2e505..a37b2b9 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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 ba391d0..5aa2a6b 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 @@
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 @@
}
}
}
+ 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 e51289b..6ad7ea7 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 @@
try {
if (mMediaQuality != null) {
if (mMediaQuality.isAutoPqSupported()) {
- mMediaQuality.getAutoPqEnabled();
+ return mMediaQuality.getAutoPqEnabled();
}
}
} catch (RemoteException e) {
@@ -1417,7 +1417,7 @@
try {
if (mMediaQuality != null) {
if (mMediaQuality.isAutoSrSupported()) {
- mMediaQuality.getAutoSrEnabled();
+ return mMediaQuality.getAutoSrEnabled();
}
}
} catch (RemoteException e) {
@@ -1449,7 +1449,7 @@
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 ef39f18..588e879 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.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 @@
private int mWarnRemoteViewsSizeBytes;
private int mStripRemoteViewsSizeBytes;
- private String[] mDefaultUnsupportedAdjustments;
+ protected String[] mDefaultUnsupportedAdjustments;
@VisibleForTesting
protected boolean mShowReviewPermissionsNotification;
@@ -4377,8 +4378,8 @@
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 @@
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 @@
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 @@
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 @@
}
} else {
mAllowedAdjustmentKeyTypes.addAll(List.of(DEFAULT_ALLOWED_ADJUSTMENT_KEY_TYPES));
- if (mDefaultUnsupportedAdjustments != null) {
- mAllowedAdjustments.removeAll(List.of(mDefaultUnsupportedAdjustments));
- }
}
}
@@ -12487,7 +12493,7 @@
}
} 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 @@
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 @@
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 @@
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 4cca855..b043d13 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 @@
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 (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 (succeeded && !doRestore && update) {
- doRestore = performRollbackManagerRestore(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 (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 (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 @@
}
}
} 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 c96c160..fbf5db5 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 @@
}
}
+ 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 9916be6..7b1eb58 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 @@
}
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 856d6a7..994ee42 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 @@
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 @@
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 b7b4cc0..48dd2eb 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.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.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 @@
@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 @@
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 @@
// 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 @@
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 42a47d4..4300b60 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 @@
@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 @@
}
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 @@
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 AppCompatAspectRatioPolicy aspectRatioPolicy =
mAppCompatController.getAspectRatioPolicy();
aspectRatioPolicy.reset();
- mIsEligibleForFixedOrientationLetterbox = false;
+ mAppCompatController.getAppCompatLetterboxPolicy()
+ .resetFixedOrientationLetterboxEligibility();
mResolveConfigHint.resolveTmpOverrides(mDisplayContent, newParentConfiguration,
isFixedRotationTransforming());
@@ -8780,28 +8779,6 @@
}
/**
- * 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 @@
// 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 @@
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 597f75a..25e38b3 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 @@
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 @@
}
}, 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 bdbd0d1..8e4d4be 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.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 @@
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 @@
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 086b11c..fa04955 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 @@
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 6074608..276c7d2 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 @@
*/
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 cc9cd90..b7d8aff 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 @@
}
@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 4494586..6a8040a 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 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 @@
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 @@
mAppCompatConfiguration = appCompatConfiguration;
}
+ void resetFixedOrientationLetterboxEligibility() {
+ mIsEligibleForFixedOrientationLetterbox = false;
+ }
+
/** Cleans up {@link Letterbox} if it exists.*/
void stop() {
mLetterboxPolicyState.stop();
@@ -91,6 +104,43 @@
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 6202f80..35fa39d 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 @@
}
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 2d0ff9b..811a39c 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 @@
@NonNull
private final AppCompatOrientationOverrides mOrientationOverrides;
@NonNull
- private final AppCompatCameraOverrides mAppCompatCameraOverrides;
+ private final AppCompatCameraOverrides mCameraOverrides;
@NonNull
private final AppCompatAspectRatioOverrides mAspectRatioOverrides;
@NonNull
@@ -46,10 +46,10 @@
@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 @@
}
@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 1ab0868..67f5b9b 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 @@
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 f5bc9f0..230cd33 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 @@
}
boolean isCameraRunningAndWindowingModeEligible(@NonNull ActivityRecord activity) {
- return activity.mAppCompatController.getAppCompatCameraOverrides()
+ return activity.mAppCompatController.getCameraOverrides()
.shouldApplyFreeformTreatmentForCameraCompat()
&& activity.inFreeformWindowingMode()
&& mCameraStateMonitor.isCameraRunningForActivity(activity);
@@ -232,7 +232,7 @@
// 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 @@
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 @@
|| !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 3c199db..dceacc3 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 @@
!= 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 @@
boolean isActivityEligibleForOrientationOverride(@NonNull ActivityRecord activity) {
return isTreatmentEnabledForDisplay()
&& isCameraRunningAndWindowingModeEligible(activity, /* mustBeFullscreen */ true)
- && activity.mAppCompatController.getAppCompatCameraOverrides()
+ && activity.mAppCompatController.getCameraOverrides()
.shouldForceRotateForCameraCompat();
}
@@ -325,7 +325,7 @@
// 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 @@
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 c6a1679..aaae160 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 @@
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 75cefdf..37cc0d2 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 @@
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 3c3a180..ad19b9a 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 @@
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 @@
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 148c968..263ada8 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.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.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 @@
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 @@
}
@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 @@
}
@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 @@
// 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 d2f8d14..d1afa38 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 @@
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 @@
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 @@
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 @@
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 @@
.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 85c5920..4330226 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 @@
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 63dafcd..c667d76 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 @@
@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 @@
configureActivityAndDisplay();
mActivityRefresher.addEvaluator(mEvaluatorTrue);
doReturn(true)
- .when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
+ .when(mActivity.mAppCompatController.getCameraOverrides())
.shouldRefreshActivityViaPauseForCameraCompat();
mActivityRefresher.onActivityConfigurationChanging(mActivity, mNewConfig, mOldConfig);
@@ -174,7 +174,7 @@
configureActivityAndDisplay();
mActivityRefresher.addEvaluator(mEvaluatorTrue);
doReturn(true)
- .when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
+ .when(mActivity.mAppCompatController.getCameraOverrides())
.shouldRefreshActivityViaPauseForCameraCompat();
mActivityRefresher.onActivityRefreshed(mActivity);
@@ -188,7 +188,7 @@
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 @@
.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 1d138e4..4ad1cd1 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 @@
}
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 576d17a..716f864 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 @@
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 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 @@
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 @@
.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 @@
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 23c767c..02b796f 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 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 @@
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 @@
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 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 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 @@
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 @@
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 a84b374..2630565 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 @@
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
- assertFalse(mActivity.isEligibleForLetterboxEducation());
+ assertFalse(mActivity.mAppCompatController.getAppCompatLetterboxPolicy()
+ .isEligibleForLetterboxEducation());
}
@Test
@@ -4694,7 +4695,8 @@
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
- assertFalse(mActivity.isEligibleForLetterboxEducation());
+ assertFalse(mActivity.mAppCompatController.getAppCompatLetterboxPolicy()
+ .isEligibleForLetterboxEducation());
}
@Test
@@ -4716,7 +4718,8 @@
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 @@
prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
- assertFalse(mActivity.isEligibleForLetterboxEducation());
+ assertFalse(mActivity.mAppCompatController.getAppCompatLetterboxPolicy()
+ .isEligibleForLetterboxEducation());
assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
}
@@ -4745,14 +4749,16 @@
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 @@
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 @@
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
- assertTrue(mActivity.isEligibleForLetterboxEducation());
+ assertTrue(mActivity.mAppCompatController.getAppCompatLetterboxPolicy()
+ .isEligibleForLetterboxEducation());
assertTrue(mActivity.mAppCompatController.getAspectRatioPolicy()
.isLetterboxedForFixedOrientationAndAspectRatio());
}
@@ -4802,7 +4811,8 @@
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 24fb8c5..da41655 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -180,7 +180,7 @@
* 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 @@
}
/**
- * 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 @@
/**
* 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 @@
/**
* 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;