Merge "Disabled two-finger dragging on TouchpadDebugView" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index 1667f2e..5d134c6 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -33228,6 +33228,7 @@
}
public interface IBinder {
+ method @FlaggedApi("android.os.binder_frozen_state_change_callback") public default void addFrozenStateChangeCallback(@NonNull android.os.IBinder.FrozenStateChangeCallback) throws android.os.RemoteException;
method public void dump(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException;
method public void dumpAsync(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException;
method @Nullable public String getInterfaceDescriptor() throws android.os.RemoteException;
@@ -33236,6 +33237,7 @@
method public void linkToDeath(@NonNull android.os.IBinder.DeathRecipient, int) throws android.os.RemoteException;
method public boolean pingBinder();
method @Nullable public android.os.IInterface queryLocalInterface(@NonNull String);
+ method @FlaggedApi("android.os.binder_frozen_state_change_callback") public default boolean removeFrozenStateChangeCallback(@NonNull android.os.IBinder.FrozenStateChangeCallback);
method public boolean transact(int, @NonNull android.os.Parcel, @Nullable android.os.Parcel, int) throws android.os.RemoteException;
method public boolean unlinkToDeath(@NonNull android.os.IBinder.DeathRecipient, int);
field public static final int DUMP_TRANSACTION = 1598311760; // 0x5f444d50
@@ -33253,6 +33255,12 @@
method public default void binderDied(@NonNull android.os.IBinder);
}
+ @FlaggedApi("android.os.binder_frozen_state_change_callback") public static interface IBinder.FrozenStateChangeCallback {
+ method public void onFrozenStateChanged(@NonNull android.os.IBinder, int);
+ field public static final int STATE_FROZEN = 0; // 0x0
+ field public static final int STATE_UNFROZEN = 1; // 0x1
+ }
+
public interface IInterface {
method public android.os.IBinder asBinder();
}
@@ -44070,7 +44078,7 @@
}
public static final class CarrierConfigManager.Gps {
- field @FlaggedApi("android.location.flags.enable_ni_supl_message_injection_by_carrier_config") public static final String KEY_ENABLE_NI_SUPL_MESSAGE_INJECTION_BOOL = "gps.enable_ni_supl_message_injection_bool";
+ field @FlaggedApi("android.location.flags.enable_ni_supl_message_injection_by_carrier_config_bugfix") public static final String KEY_ENABLE_NI_SUPL_MESSAGE_INJECTION_BOOL = "gps.enable_ni_supl_message_injection_bool";
field public static final String KEY_PERSIST_LPP_MODE_BOOL = "gps.persist_lpp_mode_bool";
field public static final String KEY_PREFIX = "gps.";
}
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index c22f46c..80546cd 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -650,13 +650,13 @@
* weakly referenced by JNI so the strong references here are needed to keep the callbacks
* around until the proxy is GC'ed.
*/
- private List<IFrozenStateChangeCallback> mFrozenStateChangeCallbacks =
+ private List<FrozenStateChangeCallback> mFrozenStateChangeCallbacks =
Collections.synchronizedList(new ArrayList<>());
/**
- * See {@link IBinder#addFrozenStateChangeCallback(IFrozenStateChangeCallback)}
+ * See {@link IBinder#addFrozenStateChangeCallback(FrozenStateChangeCallback)}
*/
- public void addFrozenStateChangeCallback(IFrozenStateChangeCallback callback)
+ public void addFrozenStateChangeCallback(FrozenStateChangeCallback callback)
throws RemoteException {
addFrozenStateChangeCallbackNative(callback);
mFrozenStateChangeCallbacks.add(callback);
@@ -665,16 +665,16 @@
/**
* See {@link IBinder#removeFrozenStateChangeCallback}
*/
- public boolean removeFrozenStateChangeCallback(IFrozenStateChangeCallback callback) {
+ public boolean removeFrozenStateChangeCallback(FrozenStateChangeCallback callback) {
mFrozenStateChangeCallbacks.remove(callback);
return removeFrozenStateChangeCallbackNative(callback);
}
- private native void addFrozenStateChangeCallbackNative(IFrozenStateChangeCallback callback)
+ private native void addFrozenStateChangeCallbackNative(FrozenStateChangeCallback callback)
throws RemoteException;
private native boolean removeFrozenStateChangeCallbackNative(
- IFrozenStateChangeCallback callback);
+ FrozenStateChangeCallback callback);
/**
* Perform a dump on the remote object
@@ -762,10 +762,9 @@
}
private static void invokeFrozenStateChangeCallback(
- IFrozenStateChangeCallback callback, IBinder binderProxy, int stateIndex) {
+ FrozenStateChangeCallback callback, IBinder binderProxy, int stateIndex) {
try {
- callback.onFrozenStateChanged(binderProxy,
- IFrozenStateChangeCallback.State.values()[stateIndex]);
+ callback.onFrozenStateChanged(binderProxy, stateIndex);
} catch (RuntimeException exc) {
Log.w("BinderNative", "Uncaught exception from frozen state change callback",
exc);
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 8185e8e..a997f4c 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -16,11 +16,15 @@
package android.os;
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import java.io.FileDescriptor;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* Base interface for a remotable object, the core part of a lightweight
@@ -377,9 +381,24 @@
*/
public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags);
- /** @hide */
- interface IFrozenStateChangeCallback {
- enum State {FROZEN, UNFROZEN};
+ /**
+ * A callback interface for receiving frozen state change events.
+ */
+ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+ interface FrozenStateChangeCallback {
+ /**
+ * @hide
+ */
+ @IntDef(prefix = {"STATE_"}, value = {
+ STATE_FROZEN,
+ STATE_UNFROZEN,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface State {
+ }
+
+ int STATE_FROZEN = 0;
+ int STATE_UNFROZEN = 1;
/**
* Interface for receiving a callback when the process hosting an IBinder
@@ -387,13 +406,13 @@
* @param who The IBinder whose hosting process has changed state.
* @param state The latest state.
*/
- void onFrozenStateChanged(@NonNull IBinder who, State state);
+ void onFrozenStateChanged(@NonNull IBinder who, @State int state);
}
/**
- * {@link addFrozenStateChangeCallback} provides a callback mechanism to notify about process
- * frozen/unfrozen events. Upon registration and any subsequent state changes, the callback is
- * invoked with the latest process frozen state.
+ * This method provides a callback mechanism to notify about process frozen/unfrozen events.
+ * Upon registration and any subsequent state changes, the callback is invoked with the latest
+ * process frozen state.
*
* <p>If the listener process (the one using this API) is itself frozen, state change events
* might be combined into a single one with the latest frozen state. This single event would
@@ -410,19 +429,19 @@
*
* <p>@throws {@link UnsupportedOperationException} if the kernel binder driver does not support
* this feature.
- * @hide
*/
- default void addFrozenStateChangeCallback(@NonNull IFrozenStateChangeCallback callback)
+ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+ default void addFrozenStateChangeCallback(@NonNull FrozenStateChangeCallback callback)
throws RemoteException {
throw new UnsupportedOperationException();
}
/**
- * Unregister a {@link IFrozenStateChangeCallback}. The callback will no longer be invoked when
+ * Unregister a {@link FrozenStateChangeCallback}. The callback will no longer be invoked when
* the hosting process changes its frozen state.
- * @hide
*/
- default boolean removeFrozenStateChangeCallback(@NonNull IFrozenStateChangeCallback callback) {
+ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+ default boolean removeFrozenStateChangeCallback(@NonNull FrozenStateChangeCallback callback) {
throw new UnsupportedOperationException();
}
}
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index 39bd15c..738d129 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -153,6 +153,14 @@
}
flag {
+ name: "binder_frozen_state_change_callback"
+ is_exported: true
+ namespace: "system_performance"
+ description: "Guards the frozen state change callback API."
+ bug: "361157077"
+}
+
+flag {
name: "message_queue_tail_tracking"
namespace: "system_performance"
description: "track tail of message queue."
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e32625e..0ada993 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -111,6 +111,7 @@
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.net.URISyntaxException;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -3022,6 +3023,9 @@
/** @hide - Private call() method to query the 'configuration' table */
public static final String CALL_METHOD_LIST_CONFIG = "LIST_config";
+ /** @hide - Private call() method to query the 'configuration' tables' namespaces */
+ public static final String CALL_METHOD_LIST_NAMESPACES_CONFIG = "LIST_namespaces_config";
+
/** @hide - Private call() method to disable / re-enable syncs to the 'configuration' table */
public static final String CALL_METHOD_SET_SYNC_DISABLED_MODE_CONFIG =
"SET_SYNC_DISABLED_MODE_config";
@@ -20458,6 +20462,10 @@
*
* The keys take the form {@code namespace/flag}, and the values are the flag values.
*
+ * Note: this API is _not_ performant, and may make a large number of
+ * Binder calls. It is intended for use in testing and debugging, and
+ * should not be used in performance-sensitive code.
+ *
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@@ -20469,13 +20477,33 @@
Bundle arg = new Bundle();
arg.putInt(Settings.CALL_METHOD_USER_KEY, resolver.getUserId());
IContentProvider cp = sProviderHolder.getProvider(resolver);
- Bundle b = cp.call(resolver.getAttributionSource(),
- sProviderHolder.mUri.getAuthority(), CALL_METHOD_LIST_CONFIG, null, arg);
- if (b != null) {
- Map<String, String> flagsToValues =
- (HashMap) b.getSerializable(Settings.NameValueTable.VALUE,
- java.util.HashMap.class);
- allFlags.putAll(flagsToValues);
+
+ if (Flags.reduceBinderTransactionSizeForGetAllProperties()) {
+ Bundle b = cp.call(resolver.getAttributionSource(),
+ sProviderHolder.mUri.getAuthority(),
+ CALL_METHOD_LIST_NAMESPACES_CONFIG, null, arg);
+ if (b != null) {
+ HashSet<String> namespaces =
+ (HashSet) b.getSerializable(Settings.NameValueTable.VALUE,
+ java.util.HashSet.class);
+ for (String namespace : namespaces) {
+ Map<String, String> keyValues =
+ getStrings(namespace, new ArrayList());
+ for (String key : keyValues.keySet()) {
+ allFlags.put(namespace + "/" + key, keyValues.get(key));
+ }
+ }
+ }
+ } else {
+ Bundle b = cp.call(resolver.getAttributionSource(),
+ sProviderHolder.mUri.getAuthority(),
+ CALL_METHOD_LIST_CONFIG, null, arg);
+ if (b != null) {
+ Map<String, String> flagsToValues =
+ (HashMap) b.getSerializable(Settings.NameValueTable.VALUE,
+ java.util.HashMap.class);
+ allFlags.putAll(flagsToValues);
+ }
}
} catch (RemoteException e) {
Log.w(TAG, "Can't query configuration table for " + CONTENT_URI, e);
diff --git a/core/java/android/provider/flags.aconfig b/core/java/android/provider/flags.aconfig
index 5c0f873..4c63673 100644
--- a/core/java/android/provider/flags.aconfig
+++ b/core/java/android/provider/flags.aconfig
@@ -52,3 +52,14 @@
description: "Enable the new ContactsContract Default Account APIs."
bug: "359957527"
}
+
+flag {
+ name: "reduce_binder_transaction_size_for_get_all_properties"
+ namespace: "core_experiments_team_internal"
+ description: "Reduce Binder transaction size in getAllProperties calls"
+ bug: "362652574"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 6b4340a..15a4715 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -38,6 +38,7 @@
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -55,7 +56,6 @@
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.window.flags.Flags;
import java.io.PrintWriter;
import java.util.Objects;
@@ -146,7 +146,7 @@
forceConsumingTypes |= type;
}
- if (Flags.enableCaptionCompatInsetForceConsumptionAlways()
+ if (ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS.isEnabled()
&& (flags & FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR) != 0) {
forceConsumingOpaqueCaptionBar = true;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9ff5031..33e7905 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -125,11 +125,11 @@
import static android.view.flags.Flags.toolkitSetFrameRateReadOnly;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
+import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme;
import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay;
-import static com.android.window.flags.Flags.enableCaptionCompatInsetForceConsumption;
import static com.android.window.flags.Flags.insetsControlChangedItem;
import static com.android.window.flags.Flags.insetsControlSeq;
import static com.android.window.flags.Flags.setScPropertiesInClient;
@@ -3214,10 +3214,10 @@
typesToShow |= Type.navigationBars();
}
if (captionIsHiddenByFlags && !captionWasHiddenByFlags
- && enableCaptionCompatInsetForceConsumption()) {
+ && ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isEnabled()) {
typesToHide |= Type.captionBar();
} else if (!captionIsHiddenByFlags && captionWasHiddenByFlags
- && enableCaptionCompatInsetForceConsumption()) {
+ && ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isEnabled()) {
typesToShow |= Type.captionBar();
}
if (typesToHide != 0) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index e1154ca..06820cd 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1003,6 +1003,55 @@
public int getActionTag() {
return SET_EMPTY_VIEW_ACTION_TAG;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(RemoteViewsProto.Action.SET_EMPTY_VIEW_ACTION);
+ out.write(RemoteViewsProto.SetEmptyViewAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ out.write(RemoteViewsProto.SetEmptyViewAction.EMPTY_VIEW_ID,
+ appResources.getResourceName(mViewId));
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.SET_EMPTY_VIEW_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.SetEmptyViewAction.VIEW_ID:
+ values.put(RemoteViewsProto.SetEmptyViewAction.VIEW_ID,
+ in.readString(RemoteViewsProto.SetEmptyViewAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.SetEmptyViewAction.EMPTY_VIEW_ID:
+ values.put(RemoteViewsProto.SetEmptyViewAction.EMPTY_VIEW_ID,
+ in.readString(RemoteViewsProto.SetEmptyViewAction.EMPTY_VIEW_ID));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values, new long[]{RemoteViewsProto.SetEmptyViewAction.VIEW_ID,
+ RemoteViewsProto.SetEmptyViewAction.EMPTY_VIEW_ID});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetEmptyViewAction.VIEW_ID);
+ int emptyViewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetEmptyViewAction.EMPTY_VIEW_ID);
+ return new SetEmptyView(viewId, emptyViewId);
+ };
+ }
}
private static class SetPendingIntentTemplate extends Action {
@@ -1243,6 +1292,68 @@
mItems.visitUris(visitor);
}
+
+ @Override
+ public boolean canWriteToProto() {
+ // Skip actions that do not contain items (intent only actions)
+ return mItems != null;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ if (mItems == null) return;
+ final long token = out.start(
+ RemoteViewsProto.Action.SET_REMOTE_COLLECTION_ITEM_LIST_ADAPTER_ACTION);
+ out.write(RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ final long itemsToken = out.start(
+ RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.ITEMS);
+ mItems.writeToProto(context, out, /* attached= */ true);
+ out.end(itemsToken);
+ out.end(token);
+ }
+ }
+
+ private PendingResources<Action> createSetRemoteCollectionItemListAdapterActionFromProto(
+ ProtoInputStream in) throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(
+ RemoteViewsProto.Action.SET_REMOTE_COLLECTION_ITEM_LIST_ADAPTER_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.VIEW_ID:
+ values.put(RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.VIEW_ID,
+ in.readString(
+ RemoteViewsProto
+ .SetRemoteCollectionItemListAdapterAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.ITEMS:
+ final long itemsToken = in.start(
+ RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.ITEMS);
+ values.put(RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.ITEMS,
+ RemoteCollectionItems.createFromProto(in));
+ in.end(itemsToken);
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values,
+ new long[]{RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.VIEW_ID,
+ RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.ITEMS});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.VIEW_ID);
+ return new SetRemoteCollectionItemListAdapterAction(viewId,
+ ((PendingResources<RemoteCollectionItems>) values.get(
+ RemoteViewsProto.SetRemoteCollectionItemListAdapterAction.ITEMS))
+ .create(context, resources, rootData, depth));
+ };
}
/**
@@ -2036,6 +2147,68 @@
public int getActionTag() {
return SET_DRAWABLE_TINT_TAG;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(RemoteViewsProto.Action.SET_DRAWABLE_TINT_ACTION);
+ out.write(RemoteViewsProto.SetDrawableTintAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ out.write(RemoteViewsProto.SetDrawableTintAction.COLOR_FILTER, mColorFilter);
+ out.write(RemoteViewsProto.SetDrawableTintAction.FILTER_MODE,
+ PorterDuff.modeToInt(mFilterMode));
+ out.write(RemoteViewsProto.SetDrawableTintAction.TARGET_BACKGROUND, mTargetBackground);
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.SET_DRAWABLE_TINT_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.SetDrawableTintAction.VIEW_ID:
+ values.put(RemoteViewsProto.SetDrawableTintAction.VIEW_ID,
+ in.readString(RemoteViewsProto.SetDrawableTintAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.SetDrawableTintAction.TARGET_BACKGROUND:
+ values.put(RemoteViewsProto.SetDrawableTintAction.TARGET_BACKGROUND,
+ in.readBoolean(
+ RemoteViewsProto.SetDrawableTintAction.TARGET_BACKGROUND));
+ break;
+ case (int) RemoteViewsProto.SetDrawableTintAction.COLOR_FILTER:
+ values.put(RemoteViewsProto.SetDrawableTintAction.COLOR_FILTER,
+ in.readInt(RemoteViewsProto.SetDrawableTintAction.COLOR_FILTER));
+ break;
+ case (int) RemoteViewsProto.SetDrawableTintAction.FILTER_MODE:
+ values.put(RemoteViewsProto.SetDrawableTintAction.FILTER_MODE,
+ PorterDuff.intToMode(in.readInt(
+ RemoteViewsProto.SetDrawableTintAction.FILTER_MODE)));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values, new long[]{RemoteViewsProto.SetDrawableTintAction.VIEW_ID});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetDrawableTintAction.VIEW_ID);
+ return new SetDrawableTint(viewId, (boolean) values.get(
+ RemoteViewsProto.SetDrawableTintAction.TARGET_BACKGROUND, false),
+ (int) values.get(RemoteViewsProto.SetDrawableTintAction.COLOR_FILTER, 0),
+ (PorterDuff.Mode) values.get(
+ RemoteViewsProto.SetDrawableTintAction.FILTER_MODE));
+ };
+ }
}
/**
@@ -2047,7 +2220,7 @@
* target {@link View#getBackground()}.
* <p>
*/
- private class SetRippleDrawableColor extends Action {
+ private static class SetRippleDrawableColor extends Action {
ColorStateList mColorStateList;
SetRippleDrawableColor(@IdRes int id, ColorStateList colorStateList) {
@@ -2082,6 +2255,58 @@
public int getActionTag() {
return SET_RIPPLE_DRAWABLE_COLOR_TAG;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(RemoteViewsProto.Action.SET_RIPPLE_DRAWABLE_COLOR_ACTION);
+ out.write(RemoteViewsProto.SetRippleDrawableColorAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ writeColorStateListToProto(out, mColorStateList,
+ RemoteViewsProto.SetRippleDrawableColorAction.COLOR_STATE_LIST);
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.SET_RIPPLE_DRAWABLE_COLOR_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.SetRippleDrawableColorAction.VIEW_ID:
+ values.put(RemoteViewsProto.SetRippleDrawableColorAction.VIEW_ID,
+ in.readString(
+ RemoteViewsProto.SetRippleDrawableColorAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.SetRippleDrawableColorAction.COLOR_STATE_LIST:
+ values.put(RemoteViewsProto.SetRippleDrawableColorAction.COLOR_STATE_LIST,
+ createColorStateListFromProto(in,
+ RemoteViewsProto
+ .SetRippleDrawableColorAction.COLOR_STATE_LIST));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values,
+ new long[]{RemoteViewsProto.SetRippleDrawableColorAction.VIEW_ID,
+ RemoteViewsProto.SetRippleDrawableColorAction.COLOR_STATE_LIST});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetRippleDrawableColorAction.VIEW_ID);
+ return new SetRippleDrawableColor(viewId, (ColorStateList) values.get(
+ RemoteViewsProto.SetRippleDrawableColorAction.COLOR_STATE_LIST));
+ };
+ }
}
/**
@@ -2987,6 +3212,82 @@
public int getActionTag() {
return RESOURCE_REFLECTION_ACTION_TAG;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(RemoteViewsProto.Action.RESOURCE_REFLECTION_ACTION);
+ out.write(RemoteViewsProto.ResourceReflectionAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ out.write(RemoteViewsProto.ResourceReflectionAction.METHOD_NAME, mMethodName);
+ out.write(RemoteViewsProto.ResourceReflectionAction.PARAMETER_TYPE, mType);
+ out.write(RemoteViewsProto.ResourceReflectionAction.RESOURCE_TYPE, mResourceType);
+ if (mResId != 0) {
+ out.write(RemoteViewsProto.ResourceReflectionAction.RES_ID,
+ appResources.getResourceName(mResId));
+ }
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.RESOURCE_REFLECTION_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.ResourceReflectionAction.VIEW_ID:
+ values.put(RemoteViewsProto.ResourceReflectionAction.VIEW_ID,
+ in.readString(RemoteViewsProto.ResourceReflectionAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.ResourceReflectionAction.METHOD_NAME:
+ values.put(RemoteViewsProto.ResourceReflectionAction.METHOD_NAME,
+ in.readString(
+ RemoteViewsProto.ResourceReflectionAction.METHOD_NAME));
+ break;
+ case (int) RemoteViewsProto.ResourceReflectionAction.RESOURCE_TYPE:
+ values.put(RemoteViewsProto.ResourceReflectionAction.RESOURCE_TYPE,
+ in.readInt(
+ RemoteViewsProto.ResourceReflectionAction.RESOURCE_TYPE));
+ break;
+ case (int) RemoteViewsProto.ResourceReflectionAction.RES_ID:
+ values.put(RemoteViewsProto.ResourceReflectionAction.RES_ID,
+ in.readString(RemoteViewsProto.ResourceReflectionAction.RES_ID));
+ break;
+ case (int) RemoteViewsProto.ResourceReflectionAction.PARAMETER_TYPE:
+ values.put(RemoteViewsProto.ResourceReflectionAction.PARAMETER_TYPE,
+ in.readInt(
+ RemoteViewsProto.ResourceReflectionAction.PARAMETER_TYPE));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values, new long[]{RemoteViewsProto.ResourceReflectionAction.VIEW_ID,
+ RemoteViewsProto.ResourceReflectionAction.METHOD_NAME,
+ RemoteViewsProto.ResourceReflectionAction.PARAMETER_TYPE});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.ResourceReflectionAction.VIEW_ID);
+
+ int resId = (values.indexOfKey(RemoteViewsProto.ResourceReflectionAction.RES_ID)
+ >= 0) ? getAsIdentifier(resources, values,
+ RemoteViewsProto.ResourceReflectionAction.RES_ID) : 0;
+ return new ResourceReflectionAction(viewId,
+ (String) values.get(RemoteViewsProto.ResourceReflectionAction.METHOD_NAME),
+ (int) values.get(RemoteViewsProto.ResourceReflectionAction.PARAMETER_TYPE),
+ (int) values.get(RemoteViewsProto.ResourceReflectionAction.RESOURCE_TYPE,
+ 0), resId);
+ };
+ }
}
private static final class AttributeReflectionAction extends BaseReflectionAction {
@@ -4593,6 +4894,61 @@
public int getActionTag() {
return SET_INT_TAG_TAG;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(RemoteViewsProto.Action.SET_INT_TAG_ACTION);
+ out.write(RemoteViewsProto.SetIntTagAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ out.write(RemoteViewsProto.SetIntTagAction.KEY,
+ appResources.getResourceName(mKey)); // rebase
+ out.write(RemoteViewsProto.SetIntTagAction.TAG, mTag);
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.SET_INT_TAG_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.SetIntTagAction.VIEW_ID:
+ values.put(RemoteViewsProto.SetIntTagAction.VIEW_ID,
+ in.readString(RemoteViewsProto.SetIntTagAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.SetIntTagAction.KEY:
+ values.put(RemoteViewsProto.SetIntTagAction.KEY,
+ in.readString(RemoteViewsProto.SetIntTagAction.KEY));
+ break;
+ case (int) RemoteViewsProto.SetIntTagAction.TAG:
+ values.put(RemoteViewsProto.SetIntTagAction.TAG,
+ in.readInt(RemoteViewsProto.SetIntTagAction.TAG));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values, new long[]{RemoteViewsProto.SetIntTagAction.VIEW_ID,
+ RemoteViewsProto.SetIntTagAction.KEY});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetIntTagAction.VIEW_ID);
+ int keyId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetIntTagAction.KEY);
+ return new SetIntTagAction(viewId, keyId,
+ (int) values.get(RemoteViewsProto.SetIntTagAction.TAG, 0));
+ };
+ }
}
private static class SetCompoundButtonCheckedAction extends Action {
@@ -4643,6 +4999,56 @@
public int getActionTag() {
return SET_COMPOUND_BUTTON_CHECKED_TAG;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(
+ RemoteViewsProto.Action.SET_COMPOUND_BUTTON_CHECKED_ACTION);
+ out.write(RemoteViewsProto.SetCompoundButtonCheckedAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ out.write(RemoteViewsProto.SetCompoundButtonCheckedAction.CHECKED, mChecked);
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.SET_COMPOUND_BUTTON_CHECKED_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.SetCompoundButtonCheckedAction.VIEW_ID:
+ values.put(RemoteViewsProto.SetCompoundButtonCheckedAction.VIEW_ID,
+ in.readString(
+ RemoteViewsProto.SetCompoundButtonCheckedAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.SetCompoundButtonCheckedAction.CHECKED:
+ values.put(RemoteViewsProto.SetCompoundButtonCheckedAction.CHECKED,
+ in.readBoolean(
+ RemoteViewsProto.SetCompoundButtonCheckedAction.CHECKED));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values,
+ new long[]{RemoteViewsProto.SetCompoundButtonCheckedAction.VIEW_ID});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetCompoundButtonCheckedAction.VIEW_ID);
+ return new SetCompoundButtonCheckedAction(viewId, (boolean) values.get(
+ RemoteViewsProto.SetCompoundButtonCheckedAction.CHECKED, false));
+ };
+ }
}
private static class SetRadioGroupCheckedAction extends Action {
@@ -4707,6 +5113,61 @@
public int getActionTag() {
return SET_RADIO_GROUP_CHECKED;
}
+
+ @Override
+ public boolean canWriteToProto() {
+ return true;
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream out, Context context, Resources appResources) {
+ final long token = out.start(RemoteViewsProto.Action.SET_RADIO_GROUP_CHECKED_ACTION);
+ out.write(RemoteViewsProto.SetRadioGroupCheckedAction.VIEW_ID,
+ appResources.getResourceName(mViewId));
+ if (mCheckedId != -1) {
+ out.write(RemoteViewsProto.SetRadioGroupCheckedAction.CHECKED_ID,
+ appResources.getResourceName(mCheckedId));
+ }
+ out.end(token);
+ }
+
+ public static PendingResources<Action> createFromProto(ProtoInputStream in)
+ throws Exception {
+ final LongSparseArray<Object> values = new LongSparseArray<>();
+
+ final long token = in.start(RemoteViewsProto.Action.SET_RADIO_GROUP_CHECKED_ACTION);
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.SetRadioGroupCheckedAction.VIEW_ID:
+ values.put(RemoteViewsProto.SetRadioGroupCheckedAction.VIEW_ID,
+ in.readString(RemoteViewsProto.SetRadioGroupCheckedAction.VIEW_ID));
+ break;
+ case (int) RemoteViewsProto.SetRadioGroupCheckedAction.CHECKED_ID:
+ values.put(RemoteViewsProto.SetRadioGroupCheckedAction.CHECKED_ID,
+ in.readString(
+ RemoteViewsProto.SetRadioGroupCheckedAction.CHECKED_ID));
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ in.end(token);
+
+ checkContainsKeys(values,
+ new long[]{RemoteViewsProto.SetRadioGroupCheckedAction.VIEW_ID});
+
+ return (context, resources, rootData, depth) -> {
+ int viewId = getAsIdentifier(resources, values,
+ RemoteViewsProto.SetRadioGroupCheckedAction.VIEW_ID);
+
+ int checkedId = (values.indexOfKey(
+ RemoteViewsProto.SetRadioGroupCheckedAction.CHECKED_ID) >= 0)
+ ? getAsIdentifier(resources, values,
+ RemoteViewsProto.SetRadioGroupCheckedAction.CHECKED_ID) : -1;
+ return new SetRadioGroupCheckedAction(viewId, checkedId);
+ };
+ }
}
private static class SetViewOutlinePreferredRadiusAction extends Action {
@@ -8450,6 +8911,7 @@
public static PendingResources<RemoteCollectionItems> createFromProto(ProtoInputStream in)
throws Exception {
final LongSparseArray<Object> values = new LongSparseArray<>();
+
values.put(RemoteViewsProto.RemoteCollectionItems.IDS, new ArrayList<Long>());
values.put(RemoteViewsProto.RemoteCollectionItems.VIEWS,
new ArrayList<PendingResources<RemoteViews>>());
@@ -9207,6 +9669,22 @@
return ReflectionAction.createFromProto(in);
case (int) RemoteViewsProto.Action.REMOVE_FROM_PARENT_ACTION:
return RemoveFromParentAction.createFromProto(in);
+ case (int) RemoteViewsProto.Action.RESOURCE_REFLECTION_ACTION:
+ return ResourceReflectionAction.createFromProto(in);
+ case (int) RemoteViewsProto.Action.SET_COMPOUND_BUTTON_CHECKED_ACTION:
+ return SetCompoundButtonCheckedAction.createFromProto(in);
+ case (int) RemoteViewsProto.Action.SET_DRAWABLE_TINT_ACTION:
+ return SetDrawableTint.createFromProto(in);
+ case (int) RemoteViewsProto.Action.SET_EMPTY_VIEW_ACTION:
+ return SetEmptyView.createFromProto(in);
+ case (int) RemoteViewsProto.Action.SET_INT_TAG_ACTION:
+ return SetIntTagAction.createFromProto(in);
+ case (int) RemoteViewsProto.Action.SET_RADIO_GROUP_CHECKED_ACTION:
+ return SetRadioGroupCheckedAction.createFromProto(in);
+ case (int) RemoteViewsProto.Action.SET_REMOTE_COLLECTION_ITEM_LIST_ADAPTER_ACTION:
+ return rv.createSetRemoteCollectionItemListAdapterActionFromProto(in);
+ case (int) RemoteViewsProto.Action.SET_RIPPLE_DRAWABLE_COLOR_ACTION:
+ return SetRippleDrawableColor.createFromProto(in);
default:
throw new RuntimeException("Unhandled field while reading Action proto!\n"
+ ProtoUtils.currentFieldToString(in));
diff --git a/core/java/android/window/flags/DesktopModeFlags.java b/core/java/android/window/flags/DesktopModeFlags.java
index 5c53d66..701b6be 100644
--- a/core/java/android/window/flags/DesktopModeFlags.java
+++ b/core/java/android/window/flags/DesktopModeFlags.java
@@ -17,7 +17,9 @@
package android.window.flags;
import android.annotation.Nullable;
-import android.content.Context;
+import android.app.ActivityThread;
+import android.app.Application;
+import android.content.ContentResolver;
import android.provider.Settings;
import android.util.Log;
@@ -39,9 +41,13 @@
*/
public enum DesktopModeFlags {
// All desktop mode related flags to be overridden by developer option toggle will be added here
- DESKTOP_WINDOWING_MODE(
+ ENABLE_DESKTOP_WINDOWING_MODE(
Flags::enableDesktopWindowingMode, /* shouldOverrideByDevOption= */ true),
- DYNAMIC_INITIAL_BOUNDS(Flags::enableWindowingDynamicInitialBounds, false);
+ ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS(Flags::enableWindowingDynamicInitialBounds, false),
+ ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION(
+ Flags::enableCaptionCompatInsetForceConsumption, true),
+ ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS(
+ Flags::enableCaptionCompatInsetForceConsumptionAlways, true);
private static final String TAG = "DesktopModeFlagsUtil";
// Function called to obtain aconfig flag value.
@@ -62,14 +68,15 @@
* Determines state of flag based on the actual flag and desktop mode developer option
* overrides.
*/
- public boolean isEnabled(Context context) {
+ public boolean isEnabled() {
+ Application application = ActivityThread.currentApplication();
if (!Flags.showDesktopWindowingDevOption()
|| !mShouldOverrideByDevOption
- || context.getContentResolver() == null) {
+ || application == null) {
return mFlagFunction.get();
} else {
boolean shouldToggleBeEnabledByDefault = Flags.enableDesktopWindowingMode();
- return switch (getToggleOverride(context)) {
+ return switch (getToggleOverride(application.getContentResolver())) {
case OVERRIDE_UNSET -> mFlagFunction.get();
// When toggle override matches its default state, don't override flags. This
// helps users reset their feature overrides.
@@ -79,14 +86,14 @@
}
}
- private ToggleOverride getToggleOverride(Context context) {
+ private ToggleOverride getToggleOverride(ContentResolver contentResolver) {
// If cached, return it
if (sCachedToggleOverride != null) {
return sCachedToggleOverride;
}
// Otherwise, fetch and cache it
- ToggleOverride override = getToggleOverrideFromSystem(context);
+ ToggleOverride override = getToggleOverrideFromSystem(contentResolver);
sCachedToggleOverride = override;
Log.d(TAG, "Toggle override initialized to: " + override);
return override;
@@ -95,9 +102,9 @@
/**
* Returns {@link ToggleOverride} from Settings.Global set by toggle.
*/
- private ToggleOverride getToggleOverrideFromSystem(Context context) {
+ private ToggleOverride getToggleOverrideFromSystem(ContentResolver contentResolver) {
int settingValue = Settings.Global.getInt(
- context.getContentResolver(),
+ contentResolver,
Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES,
ToggleOverride.OVERRIDE_UNSET.getSetting()
);
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 4708be8..84dfc49 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -38,6 +38,8 @@
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.flags.Flags.customizableWindowHeaders;
+import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
+import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
import static com.android.internal.policy.PhoneWindow.FEATURE_OPTIONS_PANEL;
@@ -114,7 +116,6 @@
import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.BackgroundFallback;
import com.android.internal.widget.floatingtoolbar.FloatingToolbar;
-import com.android.window.flags.Flags;
import java.util.List;
import java.util.concurrent.Executor;
@@ -1217,14 +1218,15 @@
final boolean hideCaptionBar = fullscreen
|| (requestedVisibleTypes & WindowInsets.Type.captionBar()) == 0;
- final boolean consumingCaptionBar = Flags.enableCaptionCompatInsetForceConsumption()
- && ((mLastForceConsumingTypes & WindowInsets.Type.captionBar()) != 0
+ final boolean consumingCaptionBar =
+ ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isEnabled()
+ && ((mLastForceConsumingTypes & WindowInsets.Type.captionBar()) != 0
&& hideCaptionBar);
final boolean isOpaqueCaptionBar = customizableWindowHeaders()
&& (appearance & APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND) == 0;
final boolean consumingOpaqueCaptionBar =
- Flags.enableCaptionCompatInsetForceConsumptionAlways()
+ ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS.isEnabled()
&& mLastForceConsumingOpaqueCaptionBar
&& isOpaqueCaptionBar;
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 90cb10a..9a4ff8f 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -290,7 +290,6 @@
"libasync_safe",
"libbinderthreadstateutils",
"libdmabufinfo",
- "libgif",
"libgui_window_info_static",
"libkernelconfigs",
"libnativehelper_lazy",
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index f2c70b5..8003bb7 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -1747,9 +1747,9 @@
{"linkToDeathNative", "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
{"unlinkToDeathNative", "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
{"addFrozenStateChangeCallbackNative",
- "(Landroid/os/IBinder$IFrozenStateChangeCallback;)V", (void*)android_os_BinderProxy_addFrozenStateChangeCallback},
+ "(Landroid/os/IBinder$FrozenStateChangeCallback;)V", (void*)android_os_BinderProxy_addFrozenStateChangeCallback},
{"removeFrozenStateChangeCallbackNative",
- "(Landroid/os/IBinder$IFrozenStateChangeCallback;)Z", (void*)android_os_BinderProxy_removeFrozenStateChangeCallback},
+ "(Landroid/os/IBinder$FrozenStateChangeCallback;)Z", (void*)android_os_BinderProxy_removeFrozenStateChangeCallback},
{"getNativeFinalizer", "()J", (void*)android_os_BinderProxy_getNativeFinalizer},
{"getExtension", "()Landroid/os/IBinder;", (void*)android_os_BinderProxy_getExtension},
};
@@ -1774,7 +1774,7 @@
"(Landroid/os/IBinder$DeathRecipient;Landroid/os/IBinder;)V");
gBinderProxyOffsets.mInvokeFrozenStateChangeCallback =
GetStaticMethodIDOrDie(env, clazz, "invokeFrozenStateChangeCallback",
- "(Landroid/os/IBinder$IFrozenStateChangeCallback;Landroid/os/"
+ "(Landroid/os/IBinder$FrozenStateChangeCallback;Landroid/os/"
"IBinder;I)V");
gBinderProxyOffsets.mNativeData = GetFieldIDOrDie(env, clazz, "mNativeData", "J");
diff --git a/core/jni/jni_wrappers.h b/core/jni/jni_wrappers.h
index 3b29e30..21b5b13 100644
--- a/core/jni/jni_wrappers.h
+++ b/core/jni/jni_wrappers.h
@@ -69,9 +69,47 @@
return static_cast<T>(res);
}
+// Inline variable that specifies the method binding format.
+// The expected format is 'XX${method}XX', where ${method} represents the original method name.
+// This variable is shared across all translation units. This is treated as a global variable as
+// per C++ 17.
+inline std::string jniMethodFormat;
+
+inline static void setJniMethodFormat(std::string value) {
+ jniMethodFormat = value;
+}
+
+// Potentially translates the given JNINativeMethods if setJniMethodFormat has been set.
+// Has no effect otherwise
+inline const JNINativeMethod* maybeRenameJniMethods(const JNINativeMethod* gMethods,
+ int numMethods) {
+ if (jniMethodFormat.empty()) {
+ return gMethods;
+ }
+ // Make a copy of gMethods with reformatted method names.
+ JNINativeMethod* modifiedMethods = new JNINativeMethod[numMethods];
+ LOG_ALWAYS_FATAL_IF(!modifiedMethods, "Failed to allocate a copy of the JNI methods");
+
+ size_t methodNamePos = jniMethodFormat.find("${method}");
+ LOG_ALWAYS_FATAL_IF(methodNamePos == std::string::npos,
+ "Invalid jniMethodFormat: could not find '${method}' in pattern");
+
+ for (int i = 0; i < numMethods; i++) {
+ modifiedMethods[i] = gMethods[i];
+ std::string modifiedName = jniMethodFormat;
+ modifiedName.replace(methodNamePos, 9, gMethods[i].name);
+ char* modifiedNameChars = new char[modifiedName.length() + 1];
+ LOG_ALWAYS_FATAL_IF(!modifiedNameChars, "Failed to allocate the new method name");
+ std::strcpy(modifiedNameChars, modifiedName.c_str());
+ modifiedMethods[i].name = modifiedNameChars;
+ }
+ return modifiedMethods;
+}
+
static inline int RegisterMethodsOrDie(JNIEnv* env, const char* className,
const JNINativeMethod* gMethods, int numMethods) {
- int res = jniRegisterNativeMethods(env, className, gMethods, numMethods);
+ const JNINativeMethod* modifiedMethods = maybeRenameJniMethods(gMethods, numMethods);
+ int res = jniRegisterNativeMethods(env, className, modifiedMethods, numMethods);
LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
return res;
}
diff --git a/core/proto/android/widget/remoteviews.proto b/core/proto/android/widget/remoteviews.proto
index 47c97b0..f477d32 100644
--- a/core/proto/android/widget/remoteviews.proto
+++ b/core/proto/android/widget/remoteviews.proto
@@ -299,6 +299,14 @@
NightModeReflectionAction night_mode_reflection_action = 5;
ReflectionAction reflection_action = 6;
RemoveFromParentAction remove_from_parent_action = 7;
+ ResourceReflectionAction resource_reflection_action = 8;
+ SetCompoundButtonCheckedAction set_compound_button_checked_action = 9;
+ SetDrawableTintAction set_drawable_tint_action = 10;
+ SetEmptyViewAction set_empty_view_action = 11;
+ SetIntTagAction set_int_tag_action = 12;
+ SetRadioGroupCheckedAction set_radio_group_checked_action = 13;
+ SetRemoteCollectionItemListAdapterAction set_remote_collection_item_list_adapter_action = 14;
+ SetRippleDrawableColorAction set_ripple_drawable_color_action = 15;
}
}
@@ -374,6 +382,52 @@
message RemoveFromParentAction {
optional string view_id = 1;
}
+
+ message ResourceReflectionAction {
+ optional string view_id = 1;
+ optional string method_name = 2;
+ optional int32 resource_type = 3;
+ optional string res_id = 4;
+ optional int32 parameter_type = 5;
+ }
+
+ message SetCompoundButtonCheckedAction {
+ optional string view_id = 1;
+ optional bool checked = 2;
+ }
+
+ message SetDrawableTintAction {
+ optional string view_id = 1;
+ optional bool target_background = 2;
+ optional int32 color_filter = 3;
+ optional int32 filter_mode = 4;
+ }
+
+ message SetEmptyViewAction {
+ optional string view_id = 1;
+ optional string empty_view_id = 2;
+ }
+
+ message SetIntTagAction {
+ optional string view_id = 1;
+ optional string key = 2;
+ optional int32 tag = 3;
+ }
+
+ message SetRadioGroupCheckedAction {
+ optional string view_id = 1;
+ optional string checked_id = 2;
+ }
+
+ message SetRemoteCollectionItemListAdapterAction {
+ optional string view_id = 1;
+ optional RemoteCollectionItems items = 2;
+ }
+
+ message SetRippleDrawableColorAction {
+ optional string view_id = 1;
+ optional android.content.res.ColorStateListProto color_state_list = 2;
+ }
}
diff --git a/core/res/res/layout/miniresolver.xml b/core/res/res/layout/miniresolver.xml
index e60e0b0..db1c779 100644
--- a/core/res/res/layout/miniresolver.xml
+++ b/core/res/res/layout/miniresolver.xml
@@ -122,7 +122,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
- android:maxLines="2"
+ android:layout_toStartOf="@id/button_open"
+ android:layout_marginEnd="8dp"
android:background="@drawable/resolver_outlined_button_bg"
style="?android:attr/borderlessButtonStyle"
android:paddingHorizontal="16dp"
@@ -136,7 +137,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
- android:maxLines="2"
android:paddingHorizontal="16dp"
android:background="@drawable/resolver_button_bg"
style="?android:attr/borderlessButtonStyle"
diff --git a/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java b/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java
index 77e8a40..fe54aa8 100644
--- a/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java
+++ b/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java
@@ -30,31 +30,30 @@
public class BfsccTestAppCmdService extends Service {
private IBfsccTestAppCmdService.Stub mBinder = new IBfsccTestAppCmdService.Stub() {
- private final LinkedBlockingQueue<IBinder.IFrozenStateChangeCallback.State> mNotifications =
+ private final LinkedBlockingQueue<Integer> mNotifications =
new LinkedBlockingQueue<>();
@Override
public void listenTo(IBinder binder) throws RemoteException {
binder.addFrozenStateChangeCallback(
- (IBinder who, IBinder.IFrozenStateChangeCallback.State state)
- -> mNotifications.offer(state));
+ (IBinder who, int state) -> mNotifications.offer(state));
}
@Override
public boolean[] waitAndConsumeNotifications() {
List<Boolean> results = new ArrayList<>();
try {
- IBinder.IFrozenStateChangeCallback.State state =
- mNotifications.poll(5, TimeUnit.SECONDS);
+ Integer state = mNotifications.poll(5, TimeUnit.SECONDS);
if (state != null) {
- results.add(state == IBinder.IFrozenStateChangeCallback.State.FROZEN);
+ results.add(
+ state.intValue() == IBinder.FrozenStateChangeCallback.STATE_FROZEN);
}
} catch (InterruptedException e) {
return null;
}
while (mNotifications.size() > 0) {
- results.add(mNotifications.poll()
- == IBinder.IFrozenStateChangeCallback.State.FROZEN);
+ results.add(mNotifications.poll().intValue()
+ == IBinder.FrozenStateChangeCallback.STATE_FROZEN);
}
boolean[] convertedResults = new boolean[results.size()];
for (int i = 0; i < results.size(); i++) {
diff --git a/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java b/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java
index ee2e7e0..195a18a 100644
--- a/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java
+++ b/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java
@@ -52,7 +52,7 @@
import java.util.concurrent.atomic.AtomicReference;
/**
- * Tests functionality of {@link android.os.IBinder.IFrozenStateChangeCallback}.
+ * Tests functionality of {@link android.os.IBinder.FrozenStateChangeCallback}.
*/
@RunWith(AndroidJUnit4.class)
@IgnoreUnderRavenwood(blockedBy = ActivityManager.class)
@@ -157,7 +157,7 @@
@Test
public void onStateChangeNotCalledAfterCallbackRemoved() throws Exception {
final LinkedBlockingQueue<Boolean> results = new LinkedBlockingQueue<>();
- IBinder.IFrozenStateChangeCallback callback;
+ IBinder.FrozenStateChangeCallback callback;
if ((callback = createCallback(mBfsccTestAppCmdService.asBinder(), results)) == null) {
return;
}
@@ -171,7 +171,7 @@
public void multipleCallbacks() throws Exception {
final LinkedBlockingQueue<Boolean> results1 = new LinkedBlockingQueue<>();
final LinkedBlockingQueue<Boolean> results2 = new LinkedBlockingQueue<>();
- IBinder.IFrozenStateChangeCallback callback1;
+ IBinder.FrozenStateChangeCallback callback1;
if ((callback1 = createCallback(mBfsccTestAppCmdService.asBinder(), results1)) == null) {
return;
}
@@ -197,8 +197,8 @@
public void onStateChangeCalledWithTheRightBinder() throws Exception {
final IBinder binder = mBfsccTestAppCmdService.asBinder();
final LinkedBlockingQueue<IBinder> results = new LinkedBlockingQueue<>();
- IBinder.IFrozenStateChangeCallback callback =
- (IBinder who, IBinder.IFrozenStateChangeCallback.State state) -> results.offer(who);
+ IBinder.FrozenStateChangeCallback callback =
+ (IBinder who, int state) -> results.offer(who);
try {
binder.addFrozenStateChangeCallback(callback);
} catch (UnsupportedOperationException e) {
@@ -221,12 +221,12 @@
}
}
- private IBinder.IFrozenStateChangeCallback createCallback(IBinder binder, Queue<Boolean> queue)
+ private IBinder.FrozenStateChangeCallback createCallback(IBinder binder, Queue<Boolean> queue)
throws RemoteException {
try {
- final IBinder.IFrozenStateChangeCallback callback =
- (IBinder who, IBinder.IFrozenStateChangeCallback.State state) ->
- queue.offer(state == IBinder.IFrozenStateChangeCallback.State.FROZEN);
+ final IBinder.FrozenStateChangeCallback callback =
+ (IBinder who, int state) ->
+ queue.offer(state == IBinder.FrozenStateChangeCallback.STATE_FROZEN);
binder.addFrozenStateChangeCallback(callback);
return callback;
} catch (UnsupportedOperationException e) {
diff --git a/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java b/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java
index 32345e6..dd40695 100644
--- a/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java
+++ b/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java
@@ -16,7 +16,7 @@
package android.window.flags;
-import static android.window.flags.DesktopModeFlags.DESKTOP_WINDOWING_MODE;
+import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE;
import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE;
import static com.android.window.flags.Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS;
@@ -75,7 +75,7 @@
public void isEnabled_devOptionFlagDisabled_overrideOff_featureFlagOn_returnsTrue() {
setOverride(OVERRIDE_OFF_SETTING);
// In absence of dev options, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isEnabled()).isTrue();
}
@@ -84,7 +84,7 @@
public void isEnabled_devOptionFlagDisabled_overrideOn_featureFlagOff_returnsFalse() {
setOverride(OVERRIDE_ON_SETTING);
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isEnabled()).isFalse();
}
@Test
@@ -93,7 +93,7 @@
setOverride(OVERRIDE_UNSET_SETTING);
// For overridableFlag, for unset overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isEnabled()).isTrue();
}
@Test
@@ -103,7 +103,7 @@
setOverride(OVERRIDE_UNSET_SETTING);
// For overridableFlag, for unset overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isEnabled()).isFalse();
}
@Test
@@ -112,7 +112,7 @@
setOverride(null);
// For overridableFlag, in absence of overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isEnabled()).isTrue();
}
@Test
@@ -122,7 +122,7 @@
setOverride(null);
// For overridableFlag, in absence of overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isEnabled()).isFalse();
}
@Test
@@ -131,7 +131,7 @@
setOverride(-2);
// For overridableFlag, for unrecognized overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isEnabled()).isTrue();
}
@Test
@@ -141,7 +141,7 @@
setOverride(-2);
// For overridableFlag, for unrecognizable overrides, follow flag
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isEnabled()).isFalse();
}
@Test
@@ -150,7 +150,7 @@
setOverride(OVERRIDE_OFF_SETTING);
// For overridableFlag, follow override if they exist
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isEnabled()).isFalse();
}
@Test
@@ -160,7 +160,7 @@
setOverride(OVERRIDE_ON_SETTING);
// For overridableFlag, follow override if they exist
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isEnabled()).isTrue();
}
@Test
@@ -169,12 +169,12 @@
setOverride(OVERRIDE_OFF_SETTING);
// For overridableFlag, follow override if they exist
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isEnabled()).isFalse();
setOverride(OVERRIDE_ON_SETTING);
// Keep overrides constant through the process
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isEnabled()).isFalse();
}
@Test
@@ -184,12 +184,12 @@
setOverride(OVERRIDE_ON_SETTING);
// For overridableFlag, follow override if they exist
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isEnabled()).isTrue();
setOverride(OVERRIDE_OFF_SETTING);
// Keep overrides constant through the process
- assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
+ assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isEnabled()).isTrue();
}
@Test
@@ -199,7 +199,7 @@
setOverride(OVERRIDE_UNSET_SETTING);
// For unset overrides, follow flag
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isEnabled()).isTrue();
}
@Test
@@ -208,7 +208,7 @@
public void isEnabled_dwFlagOn_overrideUnset_featureFlagOff_returnsFalse() {
setOverride(OVERRIDE_UNSET_SETTING);
// For unset overrides, follow flag
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isEnabled()).isFalse();
}
@Test
@@ -221,7 +221,7 @@
setOverride(OVERRIDE_ON_SETTING);
// When toggle override matches its default state (dw flag), don't override flags
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isEnabled()).isTrue();
}
@Test
@@ -231,7 +231,7 @@
setOverride(OVERRIDE_ON_SETTING);
// When toggle override matches its default state (dw flag), don't override flags
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isEnabled()).isFalse();
}
@Test
@@ -244,7 +244,7 @@
setOverride(OVERRIDE_OFF_SETTING);
// Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isEnabled()).isTrue();
}
@Test
@@ -254,7 +254,7 @@
setOverride(OVERRIDE_OFF_SETTING);
// Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isEnabled()).isFalse();
}
@Test
@@ -267,7 +267,7 @@
setOverride(OVERRIDE_UNSET_SETTING);
// For unset overrides, follow flag
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isEnabled()).isTrue();
}
@Test
@@ -280,7 +280,7 @@
setOverride(OVERRIDE_UNSET_SETTING);
// For unset overrides, follow flag
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isEnabled()).isFalse();
}
@Test
@@ -293,7 +293,7 @@
setOverride(OVERRIDE_ON_SETTING);
// Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isEnabled()).isTrue();
}
@Test
@@ -306,7 +306,7 @@
setOverride(OVERRIDE_ON_SETTING);
// Follow override if they exist, and is not equal to default toggle state (dw flag)
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isEnabled()).isFalse();
}
@Test
@@ -319,7 +319,7 @@
setOverride(OVERRIDE_OFF_SETTING);
// When toggle override matches its default state (dw flag), don't override flags
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+ assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isEnabled()).isTrue();
}
@Test
@@ -332,7 +332,7 @@
setOverride(OVERRIDE_OFF_SETTING);
// When toggle override matches its default state (dw flag), don't override flags
- assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+ assertThat(DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isEnabled()).isFalse();
}
private void setOverride(Integer setting) {
diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
index e0823b8..d6b2a78 100644
--- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -24,7 +24,6 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -190,25 +189,6 @@
assertThat(generateSessionName(cujName, tooLongTag)).isEqualTo(expectedTrimmedName);
}
- @Test
- public void validateConfiguration_surfaceOnlyAndNotDeferMonitor_throwsError() {
- Configuration.Builder builder = Configuration.Builder.withSurface(1,
- mActivity.getApplicationContext(), mSurfaceControl,
- mActivity.getMainThreadHandler()).setDeferMonitorForAnimationStart(false);
-
- assertThrows(IllegalStateException.class, builder::build);
- }
-
- @Test
- public void validateConfiguration_surfaceOnlyAndDeferMonitor_doesNotThrowError() {
- Configuration.Builder builder = Configuration.Builder.withSurface(1,
- mActivity.getApplicationContext(),
- mSurfaceControl, mActivity.getMainThreadHandler()).setDeferMonitorForAnimationStart(
- true);
-
- builder.build(); // no exception.
- }
-
private InteractionJankMonitor createMockedInteractionJankMonitor() {
InteractionJankMonitor monitor = spy(new InteractionJankMonitor(mWorker));
doReturn(true).when(monitor).shouldMonitor();
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
index 397cdcf..67de25e 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
@@ -125,12 +125,12 @@
}
@Override
- public void addFrozenStateChangeCallback(IFrozenStateChangeCallback callback)
+ public void addFrozenStateChangeCallback(FrozenStateChangeCallback callback)
throws RemoteException {
}
@Override
- public boolean removeFrozenStateChangeCallback(IFrozenStateChangeCallback callback) {
+ public boolean removeFrozenStateChangeCallback(FrozenStateChangeCallback callback) {
return false;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index dc27c82..02c818f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -862,6 +862,15 @@
handleCaptionThroughStatusBar(e, decoration);
final boolean wasDragging = mIsDragging;
updateDragStatus(e.getActionMasked());
+ final boolean upOrCancel = e.getActionMasked() == ACTION_UP
+ || e.getActionMasked() == ACTION_CANCEL;
+ if (wasDragging && upOrCancel) {
+ // When finishing a drag the event will be consumed, which means the pressed
+ // state of the App Handle must be manually reset to scale its drawable back to
+ // its original shape. This is necessary for drag gestures of the Handle that
+ // result in a cancellation (dragging back to the top).
+ v.setPressed(false);
+ }
// Only prevent onClick from receiving this event if it's a drag.
return wasDragging;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index b1fc55f..16036be 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -24,6 +24,8 @@
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
+import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
+import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;
import static com.android.launcher3.icons.BaseIconFactory.MODE_DEFAULT;
import static com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON;
@@ -604,13 +606,13 @@
// their custom content.
relayoutParams.mInputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_SPY;
} else {
- if (Flags.enableCaptionCompatInsetForceConsumption()) {
+ if (ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isEnabled()) {
// Force-consume the caption bar insets when the app tries to hide the caption.
// This improves app compatibility of immersive apps.
relayoutParams.mInsetSourceFlags |= FLAG_FORCE_CONSUMING;
}
}
- if (Flags.enableCaptionCompatInsetForceConsumptionAlways()) {
+ if (ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS.isEnabled()) {
// Always force-consume the caption bar insets for maximum app compatibility,
// including non-immersive apps that just don't handle caption insets properly.
relayoutParams.mInsetSourceFlags |= FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR;
diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp
index 1afef75..d993b87 100644
--- a/libs/input/MouseCursorController.cpp
+++ b/libs/input/MouseCursorController.cpp
@@ -64,25 +64,6 @@
mLocked.pointerSprite.clear();
}
-std::optional<FloatRect> MouseCursorController::getBounds() const {
- std::scoped_lock lock(mLock);
-
- return getBoundsLocked();
-}
-
-std::optional<FloatRect> MouseCursorController::getBoundsLocked() const REQUIRES(mLock) {
- if (!mLocked.viewport.isValid()) {
- return {};
- }
-
- return FloatRect{
- static_cast<float>(mLocked.viewport.logicalLeft),
- static_cast<float>(mLocked.viewport.logicalTop),
- static_cast<float>(mLocked.viewport.logicalRight - 1),
- static_cast<float>(mLocked.viewport.logicalBottom - 1),
- };
-}
-
void MouseCursorController::move(float deltaX, float deltaY) {
#if DEBUG_MOUSE_CURSOR_UPDATES
ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY);
@@ -105,11 +86,20 @@
}
void MouseCursorController::setPositionLocked(float x, float y) REQUIRES(mLock) {
- const auto bounds = getBoundsLocked();
- if (!bounds) return;
+ const auto& v = mLocked.viewport;
+ if (!v.isValid()) return;
- mLocked.pointerX = std::max(bounds->left, std::min(bounds->right, x));
- mLocked.pointerY = std::max(bounds->top, std::min(bounds->bottom, y));
+ // The valid bounds for a mouse cursor. Since the right and bottom edges are considered outside
+ // the display, clip the bounds by one pixel instead of letting the cursor get arbitrarily
+ // close to the outside edge.
+ const FloatRect bounds{
+ static_cast<float>(mLocked.viewport.logicalLeft),
+ static_cast<float>(mLocked.viewport.logicalTop),
+ static_cast<float>(mLocked.viewport.logicalRight - 1),
+ static_cast<float>(mLocked.viewport.logicalBottom - 1),
+ };
+ mLocked.pointerX = std::max(bounds.left, std::min(bounds.right, x));
+ mLocked.pointerY = std::max(bounds.top, std::min(bounds.bottom, y));
updatePointerLocked();
}
@@ -216,9 +206,11 @@
// Reset cursor position to center if size or display changed.
if (oldViewport.displayId != viewport.displayId || oldDisplayWidth != newDisplayWidth ||
oldDisplayHeight != newDisplayHeight) {
- if (const auto bounds = getBoundsLocked(); bounds) {
- mLocked.pointerX = (bounds->left + bounds->right) * 0.5f;
- mLocked.pointerY = (bounds->top + bounds->bottom) * 0.5f;
+ if (viewport.isValid()) {
+ // Use integer coordinates as the starting point for the cursor location.
+ // We usually expect display sizes to be even numbers, so the flooring is precautionary.
+ mLocked.pointerX = std::floor((viewport.logicalLeft + viewport.logicalRight) / 2);
+ mLocked.pointerY = std::floor((viewport.logicalTop + viewport.logicalBottom) / 2);
// Reload icon resources for density may be changed.
loadResourcesLocked(getAdditionalMouseResources);
} else {
diff --git a/libs/input/MouseCursorController.h b/libs/input/MouseCursorController.h
index 8600341..12b31a8 100644
--- a/libs/input/MouseCursorController.h
+++ b/libs/input/MouseCursorController.h
@@ -43,7 +43,6 @@
MouseCursorController(PointerControllerContext& context);
~MouseCursorController();
- std::optional<FloatRect> getBounds() const;
void move(float deltaX, float deltaY);
void setPosition(float x, float y);
FloatPoint getPosition() const;
@@ -104,7 +103,6 @@
} mLocked GUARDED_BY(mLock);
- std::optional<FloatRect> getBoundsLocked() const;
void setPositionLocked(float x, float y);
void updatePointerLocked();
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 5ae967b..78d7d3a 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -138,10 +138,6 @@
return mDisplayInfoListener->mLock;
}
-std::optional<FloatRect> PointerController::getBounds() const {
- return mCursorController.getBounds();
-}
-
void PointerController::move(float deltaX, float deltaY) {
const ui::LogicalDisplayId displayId = mCursorController.getDisplayId();
vec2 transformed;
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 4d1e1d7..ee8d121 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -51,7 +51,6 @@
~PointerController() override;
- std::optional<FloatRect> getBounds() const override;
void move(float deltaX, float deltaY) override;
void setPosition(float x, float y) override;
FloatPoint getPosition() const override;
@@ -166,9 +165,6 @@
~TouchPointerController() override;
- std::optional<FloatRect> getBounds() const override {
- LOG_ALWAYS_FATAL("Should not be called");
- }
void move(float, float) override {
LOG_ALWAYS_FATAL("Should not be called");
}
diff --git a/location/java/android/location/flags/location.aconfig b/location/java/android/location/flags/location.aconfig
index dcf5c5b..cddc337 100644
--- a/location/java/android/location/flags/location.aconfig
+++ b/location/java/android/location/flags/location.aconfig
@@ -111,6 +111,17 @@
}
flag {
+ name: "enable_ni_supl_message_injection_by_carrier_config_bugfix"
+ namespace: "location"
+ description: "Flag for enabling NI SUPL message injection by carrier config"
+ bug: "242105192"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "enable_ni_supl_message_injection_by_carrier_config"
namespace: "location"
description: "Flag for enabling NI SUPL message injection by carrier config"
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e2e7a46..cdb517b3 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -6318,7 +6318,14 @@
/**
* @hide
* Get the audio devices that would be used for the routing of the given audio attributes.
- * @param attributes the {@link AudioAttributes} for which the routing is being queried
+ * @param attributes the {@link AudioAttributes} for which the routing is being queried.
+ * For queries about output devices (playback use cases), a valid usage must be specified in
+ * the audio attributes via AudioAttributes.Builder.setUsage(). The capture preset MUST NOT
+ * be changed from default.
+ * For queries about input devices (capture use case), a valid capture preset MUST be
+ * specified in the audio attributes via AudioAttributes.Builder.setCapturePreset(). If a
+ * capture preset is present, then this has precedence over any usage or content type also
+ * present in the audio attrirutes.
* @return an empty list if there was an issue with the request, a list of audio devices
* otherwise (typically one device, except for duplicated paths).
*/
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 0b094a2..34e33c0 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1639,7 +1639,7 @@
<string name="cached_apps_freezer_reboot_dialog_text">Your device must be rebooted for this change to apply. Reboot now or cancel.</string>
<!-- Name of the 3.5mm and usb audio device. [CHAR LIMIT=50] -->
- <string name="media_transfer_wired_usb_device_name">Wired headphone</string>
+ <string name="media_transfer_wired_headphone_name">Wired headphone</string>
<!-- Name of the 3.5mm headphone, used in desktop devices. [CHAR LIMIT=50] -->
<string name="media_transfer_headphone_name">Headphone</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index 116de56..0b8fb22ce 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -90,7 +90,7 @@
name =
inputRoutingEnabledAndIsDesktop()
? context.getString(R.string.media_transfer_headphone_name)
- : context.getString(R.string.media_transfer_wired_usb_device_name);
+ : context.getString(R.string.media_transfer_wired_headphone_name);
break;
case TYPE_USB_DEVICE:
case TYPE_USB_HEADSET:
@@ -98,7 +98,7 @@
name =
inputRoutingEnabledAndIsDesktop()
? context.getString(R.string.media_transfer_usb_speaker_name)
- : context.getString(R.string.media_transfer_wired_usb_device_name);
+ : context.getString(R.string.media_transfer_wired_headphone_name);
break;
case TYPE_DOCK:
name = context.getString(R.string.media_transfer_dock_speaker_device_name);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
index 23cfc01..da5f428 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
@@ -106,12 +106,12 @@
when(mInfo.getName()).thenReturn(deviceName);
assertThat(mPhoneMediaDevice.getName())
- .isEqualTo(mContext.getString(R.string.media_transfer_wired_usb_device_name));
+ .isEqualTo(mContext.getString(R.string.media_transfer_wired_headphone_name));
when(mInfo.getType()).thenReturn(TYPE_USB_DEVICE);
assertThat(mPhoneMediaDevice.getName())
- .isEqualTo(mContext.getString(R.string.media_transfer_wired_usb_device_name));
+ .isEqualTo(mContext.getString(R.string.media_transfer_wired_headphone_name));
when(mInfo.getType()).thenReturn(TYPE_BUILTIN_SPEAKER);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index ba59ce8..0ae4da5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -545,6 +545,10 @@
reportDeviceConfigAccess(prefix);
return result;
}
+ case Settings.CALL_METHOD_LIST_NAMESPACES_CONFIG -> {
+ Bundle result = packageNamespacesForCallResult(getAllConfigFlagNamespaces());
+ return result;
+ }
case Settings.CALL_METHOD_REGISTER_MONITOR_CALLBACK_CONFIG -> {
RemoteCallback callback = args.getParcelable(
Settings.CALL_METHOD_MONITOR_CALLBACK_KEY);
@@ -1337,6 +1341,23 @@
}
@NonNull
+ private HashSet<String> getAllConfigFlagNamespaces() {
+ Set<String> flagNames = getAllConfigFlags(null).keySet();
+ HashSet<String> namespaces = new HashSet();
+ for (String name : flagNames) {
+ int slashIndex = name.indexOf("/");
+ boolean validSlashIndex = slashIndex != -1
+ && slashIndex != 0
+ && slashIndex != name.length();
+ if (validSlashIndex) {
+ String namespace = name.substring(0, slashIndex);
+ namespaces.add(namespace);
+ }
+ }
+ return namespaces;
+ }
+
+ @NonNull
private HashMap<String, String> getAllConfigFlags(@Nullable String prefix) {
if (DEBUG) {
Slog.v(LOG_TAG, "getAllConfigFlags() for " + prefix);
@@ -2561,6 +2582,12 @@
return result;
}
+ private Bundle packageNamespacesForCallResult(@NonNull HashSet<String> namespaces) {
+ Bundle result = new Bundle();
+ result.putSerializable(Settings.NameValueTable.VALUE, namespaces);
+ return result;
+ }
+
private void setMonitorCallback(RemoteCallback callback) {
if (callback == null) {
return;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
index 956c129..2028d288 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
@@ -25,6 +25,8 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.view.MotionEvent;
import android.view.accessibility.AccessibilityManager;
@@ -33,6 +35,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.testing.FakeMetricsLogger;
+import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -201,6 +204,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_NON_TOUCHSCREEN_DEVICES_BYPASS_FALSING)
public void testTrackpadGesture() {
assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isTrue();
when(mFalsingDataProvider.isFromTrackpad()).thenReturn(true);
@@ -208,6 +212,14 @@
}
@Test
+ @EnableFlags(Flags.FLAG_NON_TOUCHSCREEN_DEVICES_BYPASS_FALSING)
+ public void testTrackpadGesture_touchScreenSource_false() {
+ assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isTrue();
+ when(mFalsingDataProvider.isTouchScreenSource()).thenReturn(false);
+ assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isFalse();
+ }
+
+ @Test
public void testAddAndRemoveFalsingBeliefListener() {
verify(mHistoryTracker, never()).addBeliefListener(any());
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/FalsingDataProviderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
index df4b048..5a4799c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
@@ -312,6 +312,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_NON_TOUCHSCREEN_DEVICES_BYPASS_FALSING)
public void test_IsFromTrackpad() {
MotionEvent motionEventOrigin = appendTrackpadDownEvent(0, 0);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
index c18deb1..fac9312 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
@@ -14,22 +14,6 @@
* limitations under the License.
*/
-/*
- * 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.keyguard.domain.interactor
import android.os.PowerManager
@@ -47,7 +31,6 @@
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
import com.android.systemui.communal.domain.interactor.setCommunalAvailable
import com.android.systemui.communal.shared.model.CommunalScenes
-import com.android.systemui.communal.shared.model.CommunalTransitionKeys
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
@@ -129,7 +112,7 @@
transitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.DOZING,
- testScope
+ testScope,
)
kosmos.fakeKeyguardRepository.setBiometricUnlockState(BiometricUnlockMode.NONE)
reset(transitionRepository)
@@ -145,10 +128,7 @@
// Under default conditions, we should transition to LOCKSCREEN when waking up.
assertThat(transitionRepository)
- .startedTransition(
- from = KeyguardState.DOZING,
- to = KeyguardState.LOCKSCREEN,
- )
+ .startedTransition(from = KeyguardState.DOZING, to = KeyguardState.LOCKSCREEN)
}
@Test
@@ -166,10 +146,7 @@
// If dreaming is possible and communal is available, then we should transition to
// GLANCEABLE_HUB when waking up due to power button press.
assertThat(transitionRepository)
- .startedTransition(
- from = KeyguardState.DOZING,
- to = KeyguardState.GLANCEABLE_HUB,
- )
+ .startedTransition(from = KeyguardState.DOZING, to = KeyguardState.GLANCEABLE_HUB)
}
@Test
@@ -186,8 +163,7 @@
// If dreaming is possible and communal is available, then we should transition to
// GLANCEABLE_HUB when waking up due to power button press.
- verify(kosmos.fakeCommunalSceneRepository)
- .changeScene(CommunalScenes.Communal, CommunalTransitionKeys.Immediately)
+ verify(kosmos.fakeCommunalSceneRepository).snapToScene(CommunalScenes.Communal)
}
@Test
@@ -204,10 +180,7 @@
// If dreaming is NOT possible but communal is available, then we should transition to
// LOCKSCREEN when waking up due to power button press.
assertThat(transitionRepository)
- .startedTransition(
- from = KeyguardState.DOZING,
- to = KeyguardState.LOCKSCREEN,
- )
+ .startedTransition(from = KeyguardState.DOZING, to = KeyguardState.LOCKSCREEN)
}
@Test
@@ -224,10 +197,7 @@
// If dreaming is possible but communal is NOT available, then we should transition to
// LOCKSCREEN when waking up due to power button press.
assertThat(transitionRepository)
- .startedTransition(
- from = KeyguardState.DOZING,
- to = KeyguardState.LOCKSCREEN,
- )
+ .startedTransition(from = KeyguardState.DOZING, to = KeyguardState.LOCKSCREEN)
}
@Test
@@ -245,10 +215,7 @@
// Under default conditions, we should transition to LOCKSCREEN when waking up.
assertThat(transitionRepository)
- .startedTransition(
- from = KeyguardState.DOZING,
- to = KeyguardState.GLANCEABLE_HUB,
- )
+ .startedTransition(from = KeyguardState.DOZING, to = KeyguardState.GLANCEABLE_HUB)
}
@Test
@@ -261,10 +228,7 @@
// Waking with a SHOW_WHEN_LOCKED activity on top should transition to OCCLUDED.
assertThat(transitionRepository)
- .startedTransition(
- from = KeyguardState.DOZING,
- to = KeyguardState.OCCLUDED,
- )
+ .startedTransition(from = KeyguardState.DOZING, to = KeyguardState.OCCLUDED)
}
@Test
@@ -282,10 +246,7 @@
// Waking with a SHOW_WHEN_LOCKED activity on top should transition to OCCLUDED.
assertThat(transitionRepository)
- .startedTransition(
- from = KeyguardState.DOZING,
- to = KeyguardState.OCCLUDED,
- )
+ .startedTransition(from = KeyguardState.DOZING, to = KeyguardState.OCCLUDED)
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 40fb769..614d51e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -39,6 +39,7 @@
import android.app.IActivityManager;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.graphics.Rect;
import android.platform.test.flag.junit.FlagsParameterization;
import android.testing.TestableLooper.RunWithLooper;
import android.view.View;
@@ -53,6 +54,7 @@
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.communal.domain.interactor.CommunalInteractor;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.EnableSceneContainer;
import com.android.systemui.flags.SceneContainerFlagParameterizationKt;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.kosmos.KosmosJavaAdapter;
@@ -466,6 +468,32 @@
assertThat(lp.preferredMinDisplayRefreshRate).isEqualTo(0);
}
+ @Test
+ @EnableSceneContainer
+ public void configChanged_boundsUpdate() {
+ when(mNotificationShadeWindowView.getWidth()).thenReturn(1600);
+ when(mNotificationShadeWindowView.getHeight()).thenReturn(800);
+ when(mNotificationShadeWindowView.getVisibility()).thenReturn(View.INVISIBLE);
+ Configuration newConfig = new Configuration();
+ // swap width and height in new bounds to simulate auto-rotate
+ newConfig.windowConfiguration.setBounds(new Rect(0, 0, 800, 1600));
+ mNotificationShadeWindowController.onConfigChanged(newConfig);
+ verify(mWindowManager, atLeastOnce()).updateViewLayout(any(), any());
+ }
+
+ @Test
+ @EnableSceneContainer
+ public void configChanged_boundsDontUpdate() {
+ when(mNotificationShadeWindowView.getWidth()).thenReturn(1600);
+ when(mNotificationShadeWindowView.getHeight()).thenReturn(800);
+ when(mNotificationShadeWindowView.getVisibility()).thenReturn(View.INVISIBLE);
+ Configuration newConfig = new Configuration();
+ // same bounds as view's current bounds
+ newConfig.windowConfiguration.setBounds(new Rect(0, 0, 1600, 800));
+ mNotificationShadeWindowController.onConfigChanged(newConfig);
+ verify(mWindowManager, never()).updateViewLayout(any(), any());
+ }
+
private void setKeyguardShowing() {
mNotificationShadeWindowController.setKeyguardShowing(true);
mNotificationShadeWindowController.setKeyguardGoingAway(false);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
index 769976e..ae4b679d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
@@ -282,6 +282,8 @@
return !mRecentKeyEvents.isEmpty();
}
+ // Deprecated in favor of {@code isTouchScreenSource}, b/329221787
+ @Deprecated
public boolean isFromTrackpad() {
if (Flags.nonTouchscreenDevicesBypassFalsing()) {
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index 6e01393..ee6223f 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -146,7 +146,7 @@
screenTimeout =
systemSettings.getInt(
Settings.System.SCREEN_OFF_TIMEOUT,
- DEFAULT_SCREEN_TIMEOUT
+ DEFAULT_SCREEN_TIMEOUT,
)
}
.launchIn(bgScope)
@@ -160,7 +160,7 @@
combine(
communalSceneInteractor.currentScene,
// Emit a value on start so the combine starts.
- communalInteractor.userActivity.emitOnStart()
+ communalInteractor.userActivity.emitOnStart(),
) { scene, _ ->
// Only timeout if we're on the hub is open.
scene == CommunalScenes.Communal
@@ -219,7 +219,7 @@
}
private suspend fun determineSceneAfterTransition(
- lastStartedTransition: TransitionStep,
+ lastStartedTransition: TransitionStep
): Pair<SceneKey, TransitionKey>? {
val to = lastStartedTransition.to
val from = lastStartedTransition.from
@@ -251,9 +251,8 @@
Pair(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
}
from == KeyguardState.DOZING && to == KeyguardState.GLANCEABLE_HUB -> {
- // Make sure the communal hub is showing (immediately, not fading in) when
- // transitioning from dozing to hub.
- Pair(CommunalScenes.Communal, CommunalTransitionKeys.Immediately)
+ // Make sure the communal hub is showing when transitioning from dozing to hub.
+ Pair(CommunalScenes.Communal, CommunalTransitionKeys.SimpleFade)
}
else -> null
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt
index 11fb233..78156db 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt
@@ -30,6 +30,4 @@
val ToEditMode = TransitionKey("ToEditMode")
/** Transition to the glanceable hub after exiting edit mode */
val FromEditMode = TransitionKey("FromEditMode")
- /** Immediately transitions without any delay */
- val Immediately = TransitionKey("Immediately")
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index 80a0cee..b0820a7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -24,7 +24,6 @@
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.shared.model.CommunalScenes
-import com.android.systemui.communal.shared.model.CommunalTransitionKeys
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -95,10 +94,7 @@
scope.launch {
powerInteractor.isAwake
.filterRelevantKeyguardStateAnd { isAwake -> isAwake }
- .sample(
- keyguardInteractor.biometricUnlockState,
- ::Pair,
- )
+ .sample(keyguardInteractor.biometricUnlockState, ::Pair)
.collect {
(
_,
@@ -203,21 +199,21 @@
if (!SceneContainerFlag.isEnabled) {
startTransitionTo(
KeyguardState.GONE,
- ownerReason = "waking from dozing"
+ ownerReason = "waking from dozing",
)
}
} else if (primaryBouncerShowing) {
if (!SceneContainerFlag.isEnabled) {
startTransitionTo(
KeyguardState.PRIMARY_BOUNCER,
- ownerReason = "waking from dozing"
+ ownerReason = "waking from dozing",
)
}
} else if (isIdleOnCommunal && !communalSceneKtfRefactor()) {
if (!SceneContainerFlag.isEnabled) {
startTransitionTo(
KeyguardState.GLANCEABLE_HUB,
- ownerReason = "waking from dozing"
+ ownerReason = "waking from dozing",
)
}
} else if (isCommunalAvailable && dreamManager.canStartDreaming(true)) {
@@ -227,7 +223,7 @@
} else {
startTransitionTo(
KeyguardState.LOCKSCREEN,
- ownerReason = "waking from dozing"
+ ownerReason = "waking from dozing",
)
}
}
@@ -237,11 +233,9 @@
private suspend fun transitionToGlanceableHub() {
if (communalSceneKtfRefactor()) {
- communalSceneInteractor.changeScene(
+ communalSceneInteractor.snapToScene(
newScene = CommunalScenes.Communal,
loggingReason = "from dozing to hub",
- // Immediately show the hub when transitioning from dozing to hub.
- transitionKey = CommunalTransitionKeys.Immediately,
)
} else {
startTransitionTo(KeyguardState.GLANCEABLE_HUB)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
index 199caa1..7759298 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
@@ -162,10 +162,9 @@
.filterRelevantKeyguardStateAnd { isAsleep -> isAsleep }
.collect {
if (communalSceneKtfRefactor()) {
- communalSceneInteractor.changeScene(
+ communalSceneInteractor.snapToScene(
newScene = CommunalScenes.Blank,
loggingReason = "hub to dozing",
- transitionKey = CommunalTransitionKeys.Immediately,
keyguardState = KeyguardState.DOZING,
)
} else {
@@ -210,12 +209,12 @@
// ends, to avoid transitioning to OCCLUDED erroneously when exiting
// the dream.
.debounce(100.milliseconds),
- ::Pair
+ ::Pair,
)
.sampleFilter(
// When launching activities from widgets on the hub, we have a
// custom occlusion animation.
- communalSceneInteractor.isLaunchingWidget,
+ communalSceneInteractor.isLaunchingWidget
) { launchingWidget ->
!launchingWidget
}
@@ -253,7 +252,7 @@
noneOf(
// When launching activities from widgets on the hub, we wait to change
// scenes until the activity launch is complete.
- communalSceneInteractor.isLaunchingWidget,
+ communalSceneInteractor.isLaunchingWidget
),
)
.filterRelevantKeyguardStateAnd { isKeyguardGoingAway -> isKeyguardGoingAway }
@@ -270,7 +269,7 @@
newScene = CommunalScenes.Blank,
loggingReason = "hub to gone",
transitionKey = CommunalTransitionKeys.SimpleFade,
- keyguardState = KeyguardState.GONE
+ keyguardState = KeyguardState.GONE,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
index aa6c08e..45aad82 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
@@ -140,6 +140,7 @@
}
},
onLongClick = { tile.onLongClick(expandable) },
+ accessibilityUiState = uiState.accessibilityUiState,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index 3f3ad13..4f47536 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -28,6 +28,7 @@
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
+import android.graphics.Rect;
import android.graphics.Region;
import android.os.Binder;
import android.os.Build;
@@ -987,6 +988,19 @@
@Override
public void onConfigChanged(Configuration newConfig) {
+ // If the shade window is not visible, the bounds will not update until it becomes visible.
+ // Touches that should invoke shade expansion but are not within those incorrect bounds
+ // (because the shape of the shade window remains portrait after flipping to landscape) will
+ // be dropped, causing the shade expansion to fail silently. Since the shade doesn't open,
+ // it doesn't become visible, and the bounds will never update. Therefore, we must detect
+ // the incorrect bounds here and force the update so that touches are routed correctly.
+ if (SceneContainerFlag.isEnabled() && mWindowRootView.getVisibility() == View.INVISIBLE) {
+ Rect bounds = newConfig.windowConfiguration.getBounds();
+ if (mWindowRootView.getWidth() != bounds.width()) {
+ mLogger.logConfigChangeWidthAdjust(mWindowRootView.getWidth(), bounds.width());
+ updateRootViewBounds(bounds);
+ }
+ }
final boolean newScreenRotationAllowed = mKeyguardStateController
.isKeyguardScreenRotationAllowed();
@@ -996,6 +1010,16 @@
}
}
+ private void updateRootViewBounds(Rect bounds) {
+ int originalMlpWidth = mLp.width;
+ int originalMlpHeight = mLp.height;
+ mLp.width = bounds.width();
+ mLp.height = bounds.height();
+ mWindowManager.updateViewLayout(mWindowRootView, mLp);
+ mLp.width = originalMlpWidth;
+ mLp.height = originalMlpHeight;
+ }
+
/**
* When keyguard will be dismissed but didn't start animation yet.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
index e7a397b..1693e62 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
@@ -31,18 +31,13 @@
ConstantStringsLogger by ConstantStringsLoggerImpl(buffer, TAG) {
fun logNewState(state: Any) {
- buffer.log(
- TAG,
- DEBUG,
- { str1 = state.toString() },
- { "Applying new state: $str1" }
- )
+ buffer.log(TAG, DEBUG, { str1 = state.toString() }, { "Applying new state: $str1" })
}
private inline fun log(
logLevel: LogLevel,
initializer: LogMessage.() -> Unit,
- noinline printer: LogMessage.() -> String
+ noinline printer: LogMessage.() -> String,
) {
buffer.log(TAG, logLevel, initializer, printer)
}
@@ -52,7 +47,8 @@
TAG,
DEBUG,
{ bool1 = visible },
- { "Updating visibility, should be visible : $bool1" })
+ { "Updating visibility, should be visible : $bool1" },
+ )
}
fun logIsExpanded(
@@ -65,7 +61,7 @@
headsUpNotificationShowing: Boolean,
scrimsVisibilityNotTransparent: Boolean,
backgroundBlurRadius: Boolean,
- launchingActivityFromNotification: Boolean
+ launchingActivityFromNotification: Boolean,
) {
buffer.log(
TAG,
@@ -82,11 +78,13 @@
long2 = if (backgroundBlurRadius) 1 else 0
double1 = if (launchingActivityFromNotification) 1.0 else 0.0
},
- { "Setting isExpanded to $str1: forceWindowCollapsed $bool1, " +
+ {
+ "Setting isExpanded to $str1: forceWindowCollapsed $bool1, " +
"isKeyguardShowingAndNotOccluded $bool2, panelVisible $bool3, " +
"keyguardFadingAway $bool4, bouncerShowing $int1," +
"headsUpNotificationShowing $int2, scrimsVisibilityNotTransparent $long1," +
- "backgroundBlurRadius $long2, launchingActivityFromNotification $double1"}
+ "backgroundBlurRadius $long2, launchingActivityFromNotification $double1"
+ },
)
}
@@ -95,7 +93,7 @@
TAG,
DEBUG,
{ bool1 = visible },
- { "Updating shade, should be visible and focusable: $bool1" }
+ { "Updating shade, should be visible and focusable: $bool1" },
)
}
@@ -104,7 +102,19 @@
TAG,
DEBUG,
{ bool1 = focusable },
- { "Updating shade, should be focusable : $bool1" }
+ { "Updating shade, should be focusable : $bool1" },
+ )
+ }
+
+ fun logConfigChangeWidthAdjust(originalWidth: Int, newWidth: Int) {
+ buffer.log(
+ TAG,
+ DEBUG,
+ {
+ int1 = originalWidth
+ int2 = newWidth
+ },
+ { "Config changed. SceneWindowRootView width updating from $int1 to $int2." },
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
index 103449b..ee8ce17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
@@ -26,6 +26,7 @@
import static org.mockito.Mockito.verify;
import android.app.UiModeManager;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
import android.platform.test.annotations.EnableFlags;
@@ -78,6 +79,12 @@
mNightMode = mUiModeManager.getNightMode();
mUiModeManager.setNightMode(MODE_NIGHT_YES);
+ // Programmatically update the resource's configuration to night mode to reduce flakiness
+ Configuration nightConfig = new Configuration(mContext.getResources().getConfiguration());
+ nightConfig.uiMode = Configuration.UI_MODE_NIGHT_YES;
+ mContext.getResources().updateConfiguration(nightConfig,
+ mContext.getResources().getDisplayMetrics(), null);
+
mSpyContext = spy(mContext);
doNothing().when(mSpyContext).startActivity(any());
@@ -101,6 +108,8 @@
@Test
public void insetsOnDarkTheme_menuOnLeft_matchInsets() {
+ // In dark theme, the inset is not 0 to avoid weird spacing issue between the menu and
+ // the edge of the screen.
mMenuView.onConfigurationChanged(/* newConfig= */ null);
final InstantInsetLayerDrawable insetLayerDrawable =
(InstantInsetLayerDrawable) mMenuView.getBackground();
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
index 4cb2ce1..5d251bd 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
@@ -195,23 +195,25 @@
try {
performGlobalInitialization();
+ /*
+ * If the class has @DisabledOnRavenwood, then we'll delegate to
+ * ClassSkippingTestRunner, which simply skips it.
+ *
+ * We need to do it before instantiating TestClass for b/367694651.
+ */
+ if (isOnRavenwood() && !RavenwoodAwareTestRunnerHook.shouldRunClassOnRavenwood(
+ testClass)) {
+ mRealRunner = new ClassSkippingTestRunner(testClass);
+ mDescription = mRealRunner.getDescription();
+ return;
+ }
+
mTestClass = new TestClass(testClass);
Log.v(TAG, "RavenwoodAwareTestRunner starting for " + testClass.getCanonicalName());
onRunnerInitializing();
- /*
- * If the class has @DisabledOnRavenwood, then we'll delegate to
- * ClassSkippingTestRunner, which simply skips it.
- */
- if (isOnRavenwood() && !RavenwoodAwareTestRunnerHook.shouldRunClassOnRavenwood(
- mTestClass.getJavaClass())) {
- mRealRunner = new ClassSkippingTestRunner(mTestClass);
- mDescription = mRealRunner.getDescription();
- return;
- }
-
// Find the real runner.
final Class<? extends Runner> realRunnerClass;
final InnerRunner innerRunnerAnnotation = mTestClass.getAnnotation(InnerRunner.class);
@@ -444,14 +446,11 @@
* filter.
*/
private static class ClassSkippingTestRunner extends Runner implements Filterable {
- private final TestClass mTestClass;
private final Description mDescription;
private boolean mFilteredOut;
- ClassSkippingTestRunner(TestClass testClass) {
- mTestClass = testClass;
- mDescription = Description.createTestDescription(
- testClass.getJavaClass(), testClass.getJavaClass().getSimpleName());
+ ClassSkippingTestRunner(Class<?> testClass) {
+ mDescription = Description.createTestDescription(testClass, testClass.getSimpleName());
mFilteredOut = false;
}
diff --git a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerCallbackTest.java b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerCallbackTest.java
index 6d8fb98..09ed12d 100644
--- a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerCallbackTest.java
+++ b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerCallbackTest.java
@@ -17,12 +17,14 @@
import static org.junit.Assume.assumeTrue;
+import android.platform.test.annotations.DisabledOnRavenwood;
import android.platform.test.annotations.NoRavenizer;
import android.platform.test.ravenwood.RavenwoodAwareTestRunner;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.AfterClass;
+import org.junit.Assert;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.ClassRule;
@@ -353,4 +355,34 @@
public void test2() {
}
}
+
+ /**
+ * The test class is unloadable, but has a @DisabledOnRavenwood.
+ */
+ @RunWith(AndroidJUnit4.class)
+ @DisabledOnRavenwood
+ // CHECKSTYLE:OFF
+ @Expected("""
+ testRunStarted: classes
+ testSuiteStarted: classes
+ testSuiteStarted: ClassUnloadbleTest(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$ClassUnloadbleTest)
+ testIgnored: ClassUnloadbleTest(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$ClassUnloadbleTest)
+ testSuiteFinished: ClassUnloadbleTest(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerCallbackTest$ClassUnloadbleTest)
+ testSuiteFinished: classes
+ testRunFinished: 0,0,0,1
+ """)
+ // CHECKSTYLE:ON
+ public static class ClassUnloadbleTest {
+ static {
+ Assert.fail("Class unloadable!");
+ }
+
+ @Test
+ public void test1() {
+ }
+
+ @Test
+ public void test2() {
+ }
+ }
}
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 68d0ad2..a459ea9 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -173,6 +173,15 @@
"include-filter": "com.android.server.wm.BackgroundActivityStart*"
}
]
+ },
+ {
+ "name": "CtsOsTestCases",
+ "file_patterns": ["StorageManagerService\\.java"],
+ "options": [
+ {
+ "include-filter": "android.os.storage.cts.StorageStatsManagerTest"
+ }
+ ]
}
]
}
diff --git a/services/core/java/com/android/server/cpu/CpuMonitorService.java b/services/core/java/com/android/server/cpu/CpuMonitorService.java
index 88ff7e4..2cadbc58 100644
--- a/services/core/java/com/android/server/cpu/CpuMonitorService.java
+++ b/services/core/java/com/android/server/cpu/CpuMonitorService.java
@@ -216,7 +216,7 @@
@Override
public void onBootPhase(int phase) {
- if (phase != PHASE_BOOT_COMPLETED) {
+ if (phase != PHASE_BOOT_COMPLETED || mHandler == null) {
return;
}
Slogf.i(TAG, "Stopping periodic cpuset reading on boot complete");
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 4b2c12a..63bd9ab 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -389,7 +389,7 @@
// Reload gnss config for no SIM case
mGnssConfiguration.reloadGpsProperties();
}
- if (Flags.enableNiSuplMessageInjectionByCarrierConfig()) {
+ if (Flags.enableNiSuplMessageInjectionByCarrierConfigBugfix()) {
updateNiSuplMessageListenerRegistration(
mGnssConfiguration.isNiSuplMessageInjectionEnabled());
}
@@ -538,7 +538,7 @@
intentFilter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
mContext.registerReceiver(mIntentReceiver, intentFilter, null, mHandler);
- if (!Flags.enableNiSuplMessageInjectionByCarrierConfig()) {
+ if (!Flags.enableNiSuplMessageInjectionByCarrierConfigBugfix()) {
updateNiSuplMessageListenerRegistration(
mGnssConfiguration.isNiSuplMessageInjectionEnabled());
}
@@ -1672,7 +1672,7 @@
if (dumpAll) {
mNetworkTimeHelper.dump(pw);
pw.println("mSupportsPsds=" + mSupportsPsds);
- if (Flags.enableNiSuplMessageInjectionByCarrierConfig()) {
+ if (Flags.enableNiSuplMessageInjectionByCarrierConfigBugfix()) {
pw.println("mNiSuplMessageListenerRegistered="
+ mNiSuplMessageListenerRegistered);
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperData.java b/services/core/java/com/android/server/wallpaper/WallpaperData.java
index a698429..15f86e9 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperData.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperData.java
@@ -78,7 +78,7 @@
/**
* The component name of the currently set live wallpaper.
*/
- ComponentName wallpaperComponent;
+ private ComponentName mWallpaperComponent;
// TODO(b/347235611) Remove this field
/**
@@ -195,7 +195,7 @@
*/
WallpaperData(WallpaperData source) {
this.userId = source.userId;
- this.wallpaperComponent = source.wallpaperComponent;
+ this.mWallpaperComponent = source.mWallpaperComponent;
this.mWhich = source.mWhich;
this.wallpaperId = source.wallpaperId;
this.cropHint.set(source.cropHint);
@@ -230,6 +230,14 @@
return result;
}
+ ComponentName getComponent() {
+ return mWallpaperComponent;
+ }
+
+ void setComponent(ComponentName componentName) {
+ this.mWallpaperComponent = componentName;
+ }
+
@Override
public String toString() {
StringBuilder out = new StringBuilder(defaultString(this));
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java b/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
index b15facb..e3e83b3 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
@@ -189,13 +189,13 @@
String comp = parser.getAttributeValue(null, "component");
if (removeNextWallpaperComponent()) {
- wallpaperToParse.wallpaperComponent = comp != null
+ wallpaperToParse.setComponent(comp != null
? ComponentName.unflattenFromString(comp)
- : null;
- if (wallpaperToParse.wallpaperComponent == null
- || "android".equals(wallpaperToParse.wallpaperComponent
+ : null);
+ if (wallpaperToParse.getComponent() == null
+ || "android".equals(wallpaperToParse.getComponent()
.getPackageName())) {
- wallpaperToParse.wallpaperComponent = mImageWallpaper;
+ wallpaperToParse.setComponent(mImageWallpaper);
}
} else {
wallpaperToParse.nextWallpaperComponent = comp != null
@@ -219,7 +219,7 @@
Slog.v(TAG, "primaryColors:" + wallpaper.primaryColors);
Slog.v(TAG, "mName:" + wallpaper.name);
if (removeNextWallpaperComponent()) {
- Slog.v(TAG, "mWallpaperComponent:" + wallpaper.wallpaperComponent);
+ Slog.v(TAG, "mWallpaperComponent:" + wallpaper.getComponent());
} else {
Slog.v(TAG, "mNextWallpaperComponent:"
+ wallpaper.nextWallpaperComponent);
@@ -340,7 +340,7 @@
getAttributeInt(parser, "totalCropTop", 0),
getAttributeInt(parser, "totalCropRight", 0),
getAttributeInt(parser, "totalCropBottom", 0));
- ComponentName componentName = removeNextWallpaperComponent() ? wallpaper.wallpaperComponent
+ ComponentName componentName = removeNextWallpaperComponent() ? wallpaper.getComponent()
: wallpaper.nextWallpaperComponent;
if (multiCrop() && mImageWallpaper.equals(componentName)) {
wallpaper.mCropHints = new SparseArray<>();
@@ -480,7 +480,7 @@
out.startTag(null, tag);
out.attributeInt(null, "id", wallpaper.wallpaperId);
- if (multiCrop() && mImageWallpaper.equals(wallpaper.wallpaperComponent)) {
+ if (multiCrop() && mImageWallpaper.equals(wallpaper.getComponent())) {
if (wallpaper.mCropHints == null) {
Slog.e(TAG, "cropHints should not be null when saved");
wallpaper.mCropHints = new SparseArray<>();
@@ -580,10 +580,10 @@
}
out.attribute(null, "name", wallpaper.name);
- if (wallpaper.wallpaperComponent != null
- && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) {
+ if (wallpaper.getComponent() != null
+ && !wallpaper.getComponent().equals(mImageWallpaper)) {
out.attribute(null, "component",
- wallpaper.wallpaperComponent.flattenToShortString());
+ wallpaper.getComponent().flattenToShortString());
}
if (wallpaper.allowBackup) {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 6cc37dd..4754ffb 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -276,7 +276,7 @@
final boolean isMigration = moved && lockWallpaperChanged;
final boolean isRestore = moved && !isMigration;
final boolean isAppliedToLock = (wallpaper.mWhich & FLAG_LOCK) != 0;
- final boolean needsUpdate = wallpaper.wallpaperComponent == null
+ final boolean needsUpdate = wallpaper.getComponent() == null
|| event != CLOSE_WRITE // includes the MOVED_TO case
|| wallpaper.imageWallpaperPending;
@@ -527,7 +527,7 @@
* @return true unless the wallpaper changed during the color computation
*/
private boolean extractColors(WallpaperData wallpaper) {
- if (offloadColorExtraction()) return !mImageWallpaper.equals(wallpaper.wallpaperComponent);
+ if (offloadColorExtraction()) return !mImageWallpaper.equals(wallpaper.getComponent());
String cropFile = null;
boolean defaultImageWallpaper = false;
int wallpaperId;
@@ -550,8 +550,8 @@
synchronized (mLock) {
// Not having a wallpaperComponent means it's a lock screen wallpaper.
- final boolean imageWallpaper = mImageWallpaper.equals(wallpaper.wallpaperComponent)
- || wallpaper.wallpaperComponent == null;
+ final boolean imageWallpaper = mImageWallpaper.equals(wallpaper.getComponent())
+ || wallpaper.getComponent() == null;
if (imageWallpaper && wallpaper.getCropFile().exists()) {
cropFile = wallpaper.getCropFile().getAbsolutePath();
} else if (imageWallpaper && !wallpaper.cropExists() && !wallpaper.sourceExists()) {
@@ -824,13 +824,13 @@
return;
}
TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
- t.traceBegin("WPMS.connectLocked-" + wallpaper.wallpaperComponent);
+ t.traceBegin("WPMS.connectLocked-" + wallpaper.getComponent());
if (DEBUG) Slog.v(TAG, "Adding window token: " + mToken);
mWindowManagerInternal.addWindowToken(mToken, TYPE_WALLPAPER, mDisplayId,
null /* options */);
mWindowManagerInternal.setWallpaperShowWhenLocked(
mToken, (wallpaper.mWhich & FLAG_LOCK) != 0);
- if (multiCrop() && mImageWallpaper.equals(wallpaper.wallpaperComponent)) {
+ if (multiCrop() && mImageWallpaper.equals(wallpaper.getComponent())) {
mWindowManagerInternal.setWallpaperCropHints(mToken,
mWallpaperCropper.getRelativeCropHints(wallpaper));
} else {
@@ -906,7 +906,7 @@
}
if (!mWallpaper.wallpaperUpdating && mWallpaper.userId == mCurrentUserId) {
- Slog.w(TAG, "Wallpaper reconnect timed out for " + mWallpaper.wallpaperComponent
+ Slog.w(TAG, "Wallpaper reconnect timed out for " + mWallpaper.getComponent()
+ ", reverting to built-in wallpaper!");
clearWallpaperLocked(mWallpaper.mWhich, mWallpaper.userId, false, null);
}
@@ -1035,9 +1035,9 @@
public void onServiceDisconnected(ComponentName name) {
synchronized (mLock) {
Slog.w(TAG, "Wallpaper service gone: " + name);
- if (!Objects.equals(name, mWallpaper.wallpaperComponent)) {
+ if (!Objects.equals(name, mWallpaper.getComponent())) {
Slog.e(TAG, "Does not match expected wallpaper component "
- + mWallpaper.wallpaperComponent);
+ + mWallpaper.getComponent());
}
mService = null;
forEachDisplayConnector(connector -> connector.mEngine = null);
@@ -1065,7 +1065,7 @@
fgHandler.postDelayed(mResetRunnable, WALLPAPER_RECONNECT_TIMEOUT_MS);
if (DEBUG_LIVE) {
Slog.i(TAG,
- "Started wallpaper reconnect timeout for " + mWallpaper.wallpaperComponent);
+ "Started wallpaper reconnect timeout for " + mWallpaper.getComponent());
}
}
@@ -1081,7 +1081,7 @@
return;
}
- final ComponentName wpService = mWallpaper.wallpaperComponent;
+ final ComponentName wpService = mWallpaper.getComponent();
// The broadcast of package update could be delayed after service disconnected. Try
// to re-bind the service for 10 seconds.
mWallpaper.mBindSource = BindSource.CONNECTION_TRY_TO_REBIND;
@@ -1110,7 +1110,7 @@
// The wallpaper disappeared. If this isn't a system-default one, track
// crashes and fall back to default if it continues to misbehave.
if (this == mWallpaper.connection) {
- final ComponentName wpService = mWallpaper.wallpaperComponent;
+ final ComponentName wpService = mWallpaper.getComponent();
if (!mWallpaper.wallpaperUpdating
&& mWallpaper.userId == mCurrentUserId
&& !Objects.equals(mDefaultWallpaperComponent, wpService)
@@ -1188,7 +1188,7 @@
synchronized (mLock) {
// Do not broadcast changes on ImageWallpaper since it's handled
// internally by this class.
- boolean isImageWallpaper = mImageWallpaper.equals(mWallpaper.wallpaperComponent);
+ boolean isImageWallpaper = mImageWallpaper.equals(mWallpaper.getComponent());
if (isImageWallpaper && (!offloadColorExtraction() || primaryColors == null)) {
return;
}
@@ -1303,7 +1303,7 @@
if (mNewWallpaper.mWhich == FLAG_SYSTEM) {
// New wp is system only, so old system+lock is now lock only
final boolean originalIsStatic = mImageWallpaper.equals(
- mOriginalSystem.wallpaperComponent);
+ mOriginalSystem.getComponent());
if (originalIsStatic) {
// Static wp: image file rename has already been tried via
// migrateStaticSystemToLockWallpaperLocked() and added to the lock wp map
@@ -1314,8 +1314,7 @@
if (DEBUG) {
Slog.v(TAG, "static system+lock to system success");
}
- lockWp.wallpaperComponent =
- mOriginalSystem.wallpaperComponent;
+ lockWp.setComponent(mOriginalSystem.getComponent());
lockWp.connection = mOriginalSystem.connection;
lockWp.connection.mWallpaper = lockWp;
mOriginalSystem.mWhich = FLAG_LOCK;
@@ -1376,7 +1375,7 @@
return;
}
for (WallpaperData wallpaper: getWallpapers()) {
- final ComponentName wpService = wallpaper.wallpaperComponent;
+ final ComponentName wpService = wallpaper.getComponent();
if (wpService != null && wpService.getPackageName().equals(packageName)) {
if (DEBUG_LIVE) {
Slog.i(TAG, "Wallpaper " + wpService + " update has finished");
@@ -1402,8 +1401,8 @@
return;
}
for (WallpaperData wallpaper: getWallpapers()) {
- if (wallpaper.wallpaperComponent != null
- && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
+ if (wallpaper.getComponent() != null
+ && wallpaper.getComponent().getPackageName().equals(packageName)) {
doPackagesChangedLocked(true, wallpaper);
}
}
@@ -1417,10 +1416,10 @@
return;
}
for (WallpaperData wallpaper: getWallpapers()) {
- if (wallpaper.wallpaperComponent != null
- && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
+ if (wallpaper.getComponent() != null
+ && wallpaper.getComponent().getPackageName().equals(packageName)) {
if (DEBUG_LIVE) {
- Slog.i(TAG, "Wallpaper service " + wallpaper.wallpaperComponent
+ Slog.i(TAG, "Wallpaper service " + wallpaper.getComponent()
+ " is updating");
}
wallpaper.wallpaperUpdating = true;
@@ -1462,15 +1461,15 @@
boolean doPackagesChangedLocked(boolean doit, WallpaperData wallpaper) {
boolean changed = false;
- if (wallpaper.wallpaperComponent != null) {
- int change = isPackageDisappearing(wallpaper.wallpaperComponent
+ if (wallpaper.getComponent() != null) {
+ int change = isPackageDisappearing(wallpaper.getComponent()
.getPackageName());
if (change == PACKAGE_PERMANENT_CHANGE
|| change == PACKAGE_TEMPORARY_CHANGE) {
changed = true;
if (doit) {
Slog.w(TAG, "Wallpaper uninstalled, removing: "
- + wallpaper.wallpaperComponent);
+ + wallpaper.getComponent());
clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, false, null);
}
}
@@ -1485,15 +1484,15 @@
}
}
}
- if (wallpaper.wallpaperComponent != null
- && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) {
+ if (wallpaper.getComponent() != null
+ && isPackageModified(wallpaper.getComponent().getPackageName())) {
try {
- mContext.getPackageManager().getServiceInfo(wallpaper.wallpaperComponent,
+ mContext.getPackageManager().getServiceInfo(wallpaper.getComponent(),
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
} catch (NameNotFoundException e) {
Slog.w(TAG, "Wallpaper component gone, removing: "
- + wallpaper.wallpaperComponent);
+ + wallpaper.getComponent());
clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, false, null);
}
}
@@ -1636,8 +1635,8 @@
// sure we have something to render
boolean isImageComponent;
if (removeNextWallpaperComponent()) {
- isImageComponent = wallpaper.wallpaperComponent == null
- || mImageWallpaper.equals(wallpaper.wallpaperComponent);
+ isImageComponent = wallpaper.getComponent() == null
+ || mImageWallpaper.equals(wallpaper.getComponent());
} else {
isImageComponent = mImageWallpaper.equals(wallpaper.nextWallpaperComponent);
}
@@ -1892,10 +1891,10 @@
final ComponentName cname;
if (removeNextWallpaperComponent()) {
- cname = wallpaper.wallpaperComponent;
+ cname = wallpaper.getComponent();
} else {
- cname = (wallpaper.wallpaperComponent != null)
- ? wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
+ cname = (wallpaper.getComponent() != null)
+ ? wallpaper.getComponent() : wallpaper.nextWallpaperComponent;
}
if (!bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) {
// We failed to bind the desired wallpaper, but that might
@@ -1927,7 +1926,7 @@
// We might end up persisting the current wallpaper data
// while locked, so pretend like the component was actually
// bound into place
- wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent;
+ wallpaper.setComponent(wallpaper.nextWallpaperComponent);
}
final WallpaperData fallback = new WallpaperData(wallpaper.userId, wallpaper.mWhich);
@@ -2004,7 +2003,7 @@
// lock only case: set the system wallpaper component to both screens
if (which == FLAG_LOCK) {
- component = wallpaper.wallpaperComponent;
+ component = wallpaper.getComponent();
finalWhich = FLAG_LOCK | FLAG_SYSTEM;
} else {
component = null;
@@ -2310,7 +2309,7 @@
checkPermission(READ_WALLPAPER_INTERNAL);
WallpaperData wallpaper = (which == FLAG_LOCK) ? mLockWallpaperMap.get(userId)
: mWallpaperMap.get(userId);
- if (wallpaper == null || !mImageWallpaper.equals(wallpaper.wallpaperComponent)) {
+ if (wallpaper == null || !mImageWallpaper.equals(wallpaper.getComponent())) {
return null;
}
SparseArray<Rect> relativeSuggestedCrops =
@@ -2760,7 +2759,7 @@
WallpaperData wallpaperData = (which == FLAG_LOCK ? mLockWallpaperMap : mWallpaperMap)
.get(mCurrentUserId);
if (wallpaperData == null) return false;
- return mImageWallpaper.equals(wallpaperData.wallpaperComponent);
+ return mImageWallpaper.equals(wallpaperData.getComponent());
}
}
@@ -2996,7 +2995,7 @@
final WallpaperData originalSystemWallpaper = mWallpaperMap.get(userId);
final boolean systemIsStatic =
originalSystemWallpaper != null && mImageWallpaper.equals(
- originalSystemWallpaper.wallpaperComponent);
+ originalSystemWallpaper.getComponent());
final boolean systemIsBoth = mLockWallpaperMap.get(userId) == null;
/* If we're setting system but not lock, and lock is currently sharing the system
@@ -3190,7 +3189,7 @@
throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
}
final boolean systemIsStatic = mImageWallpaper.equals(
- originalSystemWallpaper.wallpaperComponent);
+ originalSystemWallpaper.getComponent());
final boolean systemIsBoth = mLockWallpaperMap.get(userId) == null;
if (which == FLAG_SYSTEM && systemIsBoth && systemIsStatic) {
@@ -3212,7 +3211,7 @@
liveSync = new WallpaperDestinationChangeHandler(
newWallpaper);
boolean same = changingToSame(name, newWallpaper.connection,
- newWallpaper.wallpaperComponent);
+ newWallpaper.getComponent());
/*
* If we have a shared system+lock wallpaper, and we reapply the same wallpaper
@@ -3243,7 +3242,7 @@
}
}
boolean lockBitmapCleared = false;
- if (!mImageWallpaper.equals(newWallpaper.wallpaperComponent)) {
+ if (!mImageWallpaper.equals(newWallpaper.getComponent())) {
clearWallpaperBitmaps(newWallpaper);
lockBitmapCleared = newWallpaper.mWhich == FLAG_LOCK;
}
@@ -3324,7 +3323,7 @@
}
// Has the component changed?
if (!force && changingToSame(componentName, wallpaper.connection,
- wallpaper.wallpaperComponent)) {
+ wallpaper.getComponent())) {
try {
if (DEBUG_LIVE) {
Slog.v(TAG, "Changing to the same component, ignoring");
@@ -3461,7 +3460,7 @@
return false;
}
maybeDetachLastWallpapers(wallpaper);
- wallpaper.wallpaperComponent = componentName;
+ wallpaper.setComponent(componentName);
wallpaper.connection = newConn;
newConn.mReply = reply;
updateCurrentWallpapers(wallpaper);
@@ -3586,7 +3585,7 @@
}
private void clearWallpaperComponentLocked(WallpaperData wallpaper) {
- wallpaper.wallpaperComponent = null;
+ wallpaper.setComponent(null);
detachWallpaperLocked(wallpaper);
}
@@ -3831,7 +3830,7 @@
wallpaper.wallpaperId = makeWallpaperIdLocked(); // always bump id at restore
wallpaper.allowBackup = true; // by definition if it was restored
ComponentName componentName =
- removeNextWallpaperComponent() ? wallpaper.wallpaperComponent
+ removeNextWallpaperComponent() ? wallpaper.getComponent()
: wallpaper.nextWallpaperComponent;
if (componentName != null && !componentName.equals(mImageWallpaper)) {
wallpaper.mBindSource = BindSource.RESTORE_SETTINGS_LIVE_SUCCESS;
@@ -3907,7 +3906,7 @@
if (multiCrop()) pw.print(" mCropHints="); pw.println(wallpaper.mCropHints);
pw.print(" mName="); pw.println(wallpaper.name);
pw.print(" mAllowBackup="); pw.println(wallpaper.allowBackup);
- pw.print(" mWallpaperComponent="); pw.println(wallpaper.wallpaperComponent);
+ pw.print(" mWallpaperComponent="); pw.println(wallpaper.getComponent());
pw.print(" mWallpaperDimAmount="); pw.println(wallpaper.mWallpaperDimAmount);
pw.print(" isColorExtracted="); pw.println(wallpaper.mIsColorExtractedFromDim);
pw.println(" mUidToDimAmount:");
diff --git a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
index cc6904f..156d8a0 100644
--- a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
+++ b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
@@ -103,7 +103,7 @@
final TaskDisplayArea displayArea = task.getDisplayArea();
final Rect screenBounds = displayArea.getBounds();
final Size idealSize = calculateIdealSize(screenBounds, DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
- if (!DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(activity.mWmService.mContext)) {
+ if (!DesktopModeFlags.ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isEnabled()) {
return centerInScreen(idealSize, screenBounds);
}
if (activity.mAppCompatController.getAppCompatAspectRatioOverrides()
diff --git a/services/core/java/com/android/server/wm/DesktopModeHelper.java b/services/core/java/com/android/server/wm/DesktopModeHelper.java
index 61fbb96..da76317 100644
--- a/services/core/java/com/android/server/wm/DesktopModeHelper.java
+++ b/services/core/java/com/android/server/wm/DesktopModeHelper.java
@@ -35,8 +35,8 @@
"persist.wm.debug.desktop_mode_enforce_device_restrictions", true);
/** Whether desktop mode is enabled. */
- static boolean isDesktopModeEnabled(@NonNull Context context) {
- return DesktopModeFlags.DESKTOP_WINDOWING_MODE.isEnabled(context);
+ static boolean isDesktopModeEnabled() {
+ return DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE.isEnabled();
}
/**
@@ -60,7 +60,7 @@
* Return {@code true} if desktop mode can be entered on the current device.
*/
static boolean canEnterDesktopMode(@NonNull Context context) {
- return isDesktopModeEnabled(context)
+ return isDesktopModeEnabled()
&& (!shouldEnforceDeviceRestrictions() || isDesktopModeSupported(context));
}
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 9d46529..7c3f0f2 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -35,6 +35,7 @@
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.window.TaskFragmentAnimationParams.DEFAULT_ANIMATION_BACKGROUND_COLOR;
+import static android.window.flags.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
@@ -115,7 +116,6 @@
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import com.android.server.wm.utils.AlwaysTruePredicate;
-import com.android.window.flags.Flags;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -457,7 +457,7 @@
source.setFrame(provider.getArbitraryRectangle())
.updateSideHint(getBounds())
.setBoundingRects(provider.getBoundingRects());
- if (Flags.enableCaptionCompatInsetForceConsumption()) {
+ if (ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isEnabled()) {
source.setFlags(provider.getFlags());
}
mLocalInsetsSources.put(id, source);
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 8c4448e..155e73c 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1808,9 +1808,30 @@
ATRACE_CALL();
JNIEnv* env = jniEnv();
- for (int32_t iconId = static_cast<int32_t>(PointerIconStyle::TYPE_CONTEXT_MENU);
- iconId <= static_cast<int32_t>(PointerIconStyle::TYPE_HANDWRITING); ++iconId) {
- const PointerIconStyle pointerIconStyle = static_cast<PointerIconStyle>(iconId);
+ constexpr static std::array ADDITIONAL_STYLES{PointerIconStyle::TYPE_CONTEXT_MENU,
+ PointerIconStyle::TYPE_HAND,
+ PointerIconStyle::TYPE_HELP,
+ PointerIconStyle::TYPE_WAIT,
+ PointerIconStyle::TYPE_CELL,
+ PointerIconStyle::TYPE_CROSSHAIR,
+ PointerIconStyle::TYPE_TEXT,
+ PointerIconStyle::TYPE_VERTICAL_TEXT,
+ PointerIconStyle::TYPE_ALIAS,
+ PointerIconStyle::TYPE_COPY,
+ PointerIconStyle::TYPE_NO_DROP,
+ PointerIconStyle::TYPE_ALL_SCROLL,
+ PointerIconStyle::TYPE_HORIZONTAL_DOUBLE_ARROW,
+ PointerIconStyle::TYPE_VERTICAL_DOUBLE_ARROW,
+ PointerIconStyle::TYPE_TOP_RIGHT_DOUBLE_ARROW,
+ PointerIconStyle::TYPE_TOP_LEFT_DOUBLE_ARROW,
+ PointerIconStyle::TYPE_ZOOM_IN,
+ PointerIconStyle::TYPE_ZOOM_OUT,
+ PointerIconStyle::TYPE_GRAB,
+ PointerIconStyle::TYPE_GRABBING,
+ PointerIconStyle::TYPE_HANDWRITING,
+ PointerIconStyle::TYPE_SPOT_HOVER};
+
+ for (const auto pointerIconStyle : ADDITIONAL_STYLES) {
PointerIcon pointerIcon = loadPointerIcon(env, displayId, pointerIconStyle);
(*outResources)[pointerIconStyle] = toSpriteIcon(pointerIcon);
if (!pointerIcon.bitmapFrames.empty()) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
index 8b65337..32135f1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
@@ -22,9 +22,10 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
@@ -36,6 +37,7 @@
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
import android.os.Process;
+import android.os.RemoteException;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
@@ -137,9 +139,17 @@
mSensitiveContentProtectionManagerService.mNotificationListener =
spy(mSensitiveContentProtectionManagerService.mNotificationListener);
- doCallRealMethod()
- .when(mSensitiveContentProtectionManagerService.mNotificationListener)
- .onListenerConnected();
+
+ // Unexpected NLS interactions when registered cause test flakes. For purposes of this test,
+ // the test will control any NLS calls.
+ try {
+ doNothing().when(mSensitiveContentProtectionManagerService.mNotificationListener)
+ .registerAsSystemService(any(), any(), anyInt());
+ doNothing().when(mSensitiveContentProtectionManagerService.mNotificationListener)
+ .unregisterAsSystemService();
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
// Setup RankingMap and two possilbe rankings
when(mSensitiveRanking.hasSensitiveContent()).thenReturn(true);
diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
index 15ae463..0b762df 100644
--- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
@@ -290,7 +290,7 @@
final WallpaperData fallbackData = mService.mFallbackWallpaper;
assertEquals("Fallback wallpaper component should be ImageWallpaper.",
- sImageWallpaperComponentName, fallbackData.wallpaperComponent);
+ sImageWallpaperComponentName, fallbackData.getComponent());
verifyLastWallpaperData(USER_SYSTEM, sDefaultWallpaperComponent);
verifyDisplayData();
@@ -580,7 +580,7 @@
final WallpaperData lastData = mService.mLastWallpaper;
assertNotNull("Last wallpaper must not be null", lastData);
assertEquals("Last wallpaper component must be equals.", expectedComponent,
- lastData.wallpaperComponent);
+ lastData.getComponent());
assertEquals("The user id in last wallpaper should be the last switched user",
lastUserId, lastData.userId);
assertNotNull("Must exist user data connection on last wallpaper data",
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 41223db..2ef0573 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -5038,7 +5038,7 @@
* {@code true} - Enable NI SUPL message injection.
*/
@FlaggedApi(android.location.flags.Flags
- .FLAG_ENABLE_NI_SUPL_MESSAGE_INJECTION_BY_CARRIER_CONFIG)
+ .FLAG_ENABLE_NI_SUPL_MESSAGE_INJECTION_BY_CARRIER_CONFIG_BUGFIX)
public static final String KEY_ENABLE_NI_SUPL_MESSAGE_INJECTION_BOOL =
KEY_PREFIX + "enable_ni_supl_message_injection_bool";
@@ -5059,7 +5059,7 @@
defaults.putInt(KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
SUPL_EMERGENCY_MODE_TYPE_CP_ONLY);
defaults.putStringArray(KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY, null);
- if (android.location.flags.Flags.enableNiSuplMessageInjectionByCarrierConfig()) {
+ if (android.location.flags.Flags.enableNiSuplMessageInjectionByCarrierConfigBugfix()) {
defaults.putBoolean(KEY_ENABLE_NI_SUPL_MESSAGE_INJECTION_BOOL, false);
}
return defaults;
diff --git a/tests/Tracing/Android.bp b/tests/Tracing/Android.bp
index 5a7f12f..90998e6 100644
--- a/tests/Tracing/Android.bp
+++ b/tests/Tracing/Android.bp
@@ -15,7 +15,7 @@
},
// Include some source files directly to be able to access package members
srcs: ["src/**/*.java"],
- libs: ["android.test.runner"],
+ libs: ["android.test.runner.stubs.system"],
static_libs: [
"junit",
"androidx.test.rules",
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt
index 290e7be..9467434 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt
@@ -22,6 +22,7 @@
import com.google.android.lint.aidl.EnforcePermissionDetector
import com.google.android.lint.aidl.PermissionAnnotationDetector
import com.google.android.lint.aidl.SimpleManualPermissionEnforcementDetector
+import com.google.android.lint.aidl.SimpleRequiresNoPermissionDetector
import com.google.auto.service.AutoService
@AutoService(IssueRegistry::class)
@@ -34,6 +35,7 @@
EnforcePermissionDetector.ISSUE_MISUSING_ENFORCE_PERMISSION,
PermissionAnnotationDetector.ISSUE_MISSING_PERMISSION_ANNOTATION,
SimpleManualPermissionEnforcementDetector.ISSUE_SIMPLE_MANUAL_PERMISSION_ENFORCEMENT,
+ SimpleRequiresNoPermissionDetector.ISSUE_SIMPLE_REQUIRES_NO_PERMISSION,
)
override val api: Int
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetector.kt
new file mode 100644
index 0000000..1a13c02
--- /dev/null
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetector.kt
@@ -0,0 +1,118 @@
+/*
+ * 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.google.android.lint.aidl
+
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import org.jetbrains.uast.UastCallKind
+import org.jetbrains.uast.UBlockExpression
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UMethod
+import org.jetbrains.uast.visitor.AbstractUastVisitor
+
+/**
+ * Ensures all AIDL implementations hosted by system_server which don't call other methods are
+ * annotated with @RequiresNoPermission. AIDL Interfaces part of `exemptAidlInterfaces` are skipped
+ * during this search to ensure the detector targets only new AIDL Interfaces.
+ */
+class SimpleRequiresNoPermissionDetector : AidlImplementationDetector() {
+ override fun visitAidlMethod(
+ context: JavaContext,
+ node: UMethod,
+ interfaceName: String,
+ body: UBlockExpression
+ ) {
+ if (!isSystemServicePath(context)) return
+ if (context.evaluator.isAbstract(node)) return
+
+ val fullyQualifiedInterfaceName =
+ getContainingAidlInterfaceQualified(context, node) ?: return
+ if (exemptAidlInterfaces.contains(fullyQualifiedInterfaceName)) return
+
+ if (node.hasAnnotation(ANNOTATION_REQUIRES_NO_PERMISSION)) return
+
+ if (!isCallingMethod(node)) {
+ context.report(
+ ISSUE_SIMPLE_REQUIRES_NO_PERMISSION,
+ node,
+ context.getLocation(node),
+ """
+ Method ${node.name} doesn't perform any permission checks, meaning it should \
+ be annotated with @RequiresNoPermission.
+ """.trimMargin()
+ )
+ }
+ }
+
+ private fun isCallingMethod(node: UMethod): Boolean {
+ val uCallExpressionVisitor = UCallExpressionVisitor()
+ node.accept(uCallExpressionVisitor)
+
+ return uCallExpressionVisitor.isCallingMethod
+ }
+
+ /**
+ * Visits the body of a `UMethod` and determines if it encounters a `UCallExpression` which is
+ * a `UastCallKind.METHOD_CALL`. `isCallingMethod` will hold the result of the search procedure.
+ */
+ private class UCallExpressionVisitor : AbstractUastVisitor() {
+ var isCallingMethod = false
+
+ override fun visitElement(node: UElement): Boolean {
+ // Stop the search early when a method call has been found.
+ return isCallingMethod
+ }
+
+ override fun visitCallExpression(node: UCallExpression): Boolean {
+ if (node.kind != UastCallKind.METHOD_CALL) return false
+
+ isCallingMethod = true
+ return true
+ }
+ }
+
+ companion object {
+
+ private val EXPLANATION = """
+ Method implementations of AIDL Interfaces hosted by the `system_server` which do not
+ call any other methods should be annotated with @RequiresNoPermission. That is because
+ not calling any other methods implies that the method does not perform any permission
+ checking.
+
+ Please migrate to an @RequiresNoPermission annotation.
+ """.trimIndent()
+
+ @JvmField
+ val ISSUE_SIMPLE_REQUIRES_NO_PERMISSION = Issue.create(
+ id = "SimpleRequiresNoPermission",
+ briefDescription = "System Service APIs not calling other methods should use @RNP",
+ explanation = EXPLANATION,
+ category = Category.SECURITY,
+ priority = 5,
+ severity = Severity.ERROR,
+ implementation = Implementation(
+ SimpleRequiresNoPermissionDetector::class.java,
+ Scope.JAVA_FILE_SCOPE
+ ),
+ )
+ }
+}
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt
index 92d0829..824be93 100644
--- a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt
@@ -17,7 +17,6 @@
package com.google.android.lint.aidl
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
-import com.android.tools.lint.checks.infrastructure.TestFile
import com.android.tools.lint.checks.infrastructure.TestLintTask
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
@@ -64,7 +63,7 @@
"""
package com.android.server;
public class Bar extends IBar.Stub {
- public void testMethod() { }
+ public void testMethod(int parameter1, int parameter2) { }
}
"""
)
@@ -75,8 +74,8 @@
.expect(
"""
src/frameworks/base/services/java/com/android/server/Bar.java:3: Error: The method testMethod is not permission-annotated. [MissingPermissionAnnotation]
- public void testMethod() { }
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ public void testMethod(int parameter1, int parameter2) { }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 errors, 0 warnings
"""
)
@@ -90,7 +89,7 @@
"""
package com.android.server;
public class Bar extends IBar.Stub {
- public void testMethod() { }
+ public void testMethod(int parameter1, int parameter2) { }
}
"""
)
@@ -132,7 +131,7 @@
"""
package com.android.server;
public abstract class Bar extends IBar.Stub {
- public abstract void testMethod();
+ public abstract void testMethod(int parameter1, int parameter2);
}
"""
)
@@ -177,50 +176,6 @@
.expectClean()
}
- /* Stubs */
-
- // A service with permission annotation on the method.
- private val interfaceIFoo: TestFile = java(
- """
- public interface IFoo extends android.os.IInterface {
- public static abstract class Stub extends android.os.Binder implements IFoo {
- }
- @Override
- @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
- public void testMethod();
- @Override
- @android.annotation.RequiresNoPermission
- public void testMethodNoPermission();
- @Override
- @android.annotation.PermissionManuallyEnforced
- public void testMethodManual();
- }
- """
- ).indented()
-
- // A service with no permission annotation.
- private val interfaceIBar: TestFile = java(
- """
- public interface IBar extends android.os.IInterface {
- public static abstract class Stub extends android.os.Binder implements IBar {
- }
- public void testMethod();
- }
- """
- ).indented()
-
- // A service whose AIDL Interface is exempted.
- private val interfaceIExempted: TestFile = java(
- """
- package android.accessibilityservice;
- public interface IBrailleDisplayConnection extends android.os.IInterface {
- public static abstract class Stub extends android.os.Binder implements IBrailleDisplayConnection {
- }
- public void testMethod();
- }
- """
- ).indented()
-
private val stubs = arrayOf(interfaceIFoo, interfaceIBar, interfaceIExempted)
private fun createVisitedPath(filename: String) =
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetectorTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetectorTest.kt
new file mode 100644
index 0000000..a33b48c
--- /dev/null
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetectorTest.kt
@@ -0,0 +1,244 @@
+/*
+ * 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.google.android.lint.aidl
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+
+class SimpleRequiresNoPermissionDetectorTest : LintDetectorTest() {
+ override fun getDetector(): Detector = SimpleRequiresNoPermissionDetector()
+ override fun getIssues(): List<Issue> = listOf(
+ SimpleRequiresNoPermissionDetector
+ .ISSUE_SIMPLE_REQUIRES_NO_PERMISSION
+ )
+
+ override fun lint(): TestLintTask = super.lint().allowMissingSdk()
+
+ fun testRequiresNoPermissionUsedCorrectly_shouldNotWarn() {
+ lint()
+ .files(
+ java(
+ createVisitedPath("Foo.java"),
+ """
+ package com.android.server;
+ public class Foo extends IFoo.Stub {
+ private int memberInt;
+
+ @Override
+ @android.annotation.RequiresNoPermission
+ public void testMethodNoPermission(int parameter1, int parameter2) {
+ if (parameter1 < parameter2) {
+ memberInt = parameter1;
+ } else {
+ memberInt = parameter2;
+ }
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expectClean()
+ }
+
+ fun testMissingRequiresNoPermission_shouldWarn() {
+ lint()
+ .files(
+ java(
+ createVisitedPath("Bar.java"),
+ """
+ package com.android.server;
+ public class Bar extends IBar.Stub {
+ private int memberInt;
+
+ @Override
+ public void testMethod(int parameter1, int parameter2) {
+ if (parameter1 < parameter2) {
+ memberInt = parameter1;
+ } else {
+ memberInt = parameter2;
+ }
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expect(
+ """
+ src/frameworks/base/services/java/com/android/server/Bar.java:5: Error: Method testMethod doesn't perform any permission checks, meaning it should be annotated with @RequiresNoPermission. [SimpleRequiresNoPermission]
+ @Override
+ ^
+ 1 errors, 0 warnings
+ """
+ )
+ }
+
+ fun testMethodOnlyPerformsConstructorCall_shouldWarn() {
+ lint()
+ .files(
+ java(
+ createVisitedPath("Bar.java"),
+ """
+ package com.android.server;
+ public class Bar extends IBar.Stub {
+ private IntPair memberIntPair;
+
+ @Override
+ public void testMethod(int parameter1, int parameter2) {
+ memberIntPair = new IntPair(parameter1, parameter2);
+ }
+
+ private static class IntPair {
+ public int first;
+ public int second;
+
+ public IntPair(int first, int second) {
+ this.first = first;
+ this.second = second;
+ }
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expect(
+ """
+ src/frameworks/base/services/java/com/android/server/Bar.java:5: Error: Method testMethod doesn't perform any permission checks, meaning it should be annotated with @RequiresNoPermission. [SimpleRequiresNoPermission]
+ @Override
+ ^
+ 1 errors, 0 warnings
+ """
+ )
+ }
+
+ fun testMissingRequiresNoPermissionInIgnoredDirectory_shouldNotWarn() {
+ lint()
+ .files(
+ java(
+ ignoredPath,
+ """
+ package com.android.server;
+ public class Bar extends IBar.Stub {
+ @Override
+ public void testMethod(int parameter1, int parameter2) {}
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expectClean()
+ }
+
+ fun testMissingRequiresNoPermissionAbstractMethod_shouldNotWarn() {
+ lint()
+ .files(
+ java(
+ createVisitedPath("Bar.java"),
+ """
+ package com.android.server;
+ public abstract class Bar extends IBar.Stub {
+ private int memberInt;
+
+ @Override
+ public abstract void testMethodNoPermission(int parameter1, int parameter2);
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expectClean()
+ }
+
+ // If this test fails, consider the following steps:
+ // 1. Pick the first entry (interface) from `exemptAidlInterfaces`.
+ // 2. Change `interfaceIExempted` to use that interface.
+ // 3. Change this test's class to extend the interface's Stub.
+ fun testMissingRequiresNoPermissionAidlInterfaceExempted_shouldNotWarn() {
+ lint()
+ .files(
+ java(
+ createVisitedPath("Bar.java"),
+ """
+ package com.android.server;
+ public class Bar extends android.accessibilityservice.IBrailleDisplayConnection.Stub {
+ public void testMethod(int parameter1, int parameter2) {}
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expectClean()
+ }
+
+ fun testMethodMakesAnotherMethodCall_shouldNotWarn() {
+ lint()
+ .files(
+ java(
+ createVisitedPath("Bar.java"),
+ """
+ package com.android.server;
+ public class Bar extends IBar.Stub {
+ private int memberInt;
+
+ @Override
+ public void testMethod(int parameter1, int parameter2) {
+ if (!hasPermission()) return;
+
+ if (parameter1 < parameter2) {
+ memberInt = parameter1;
+ } else {
+ memberInt = parameter2;
+ }
+ }
+
+ private bool hasPermission() {
+ // Perform a permission check.
+ return true;
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .run()
+ .expectClean()
+ }
+
+ private val stubs = arrayOf(interfaceIFoo, interfaceIBar, interfaceIExempted)
+
+ private fun createVisitedPath(filename: String) =
+ "src/frameworks/base/services/java/com/android/server/$filename"
+
+ private val ignoredPath = "src/test/pkg/TestClass.java"
+}
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt
index 2ec8fdd..18a8f18 100644
--- a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt
@@ -85,4 +85,46 @@
}
}
""".trimIndent()
-)
\ No newline at end of file
+)
+
+// A service with permission annotation on the method.
+val interfaceIFoo: TestFile = java(
+ """
+ public interface IFoo extends android.os.IInterface {
+ public static abstract class Stub extends android.os.Binder implements IFoo {
+ }
+ @Override
+ @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
+ public void testMethod();
+ @Override
+ @android.annotation.RequiresNoPermission
+ public void testMethodNoPermission(int parameter1, int parameter2);
+ @Override
+ @android.annotation.PermissionManuallyEnforced
+ public void testMethodManual();
+ }
+ """
+).indented()
+
+// A service with no permission annotation.
+val interfaceIBar: TestFile = java(
+ """
+ public interface IBar extends android.os.IInterface {
+ public static abstract class Stub extends android.os.Binder implements IBar {
+ }
+ public void testMethod(int parameter1, int parameter2);
+ }
+ """
+).indented()
+
+// A service whose AIDL Interface is exempted.
+val interfaceIExempted: TestFile = java(
+ """
+ package android.accessibilityservice;
+ public interface IBrailleDisplayConnection extends android.os.IInterface {
+ public static abstract class Stub extends android.os.Binder implements IBrailleDisplayConnection {
+ }
+ public void testMethod();
+ }
+ """
+).indented()