Merge "Prefer defining local variables over userData.mBindingController" into main
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 624227d..14ae3f5 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -4260,6 +4260,12 @@
field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentOrganizerToken> CREATOR;
}
+ public final class TaskFragmentParentInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentParentInfo> CREATOR;
+ }
+
public final class TaskFragmentTransaction implements android.os.Parcelable {
ctor public TaskFragmentTransaction();
method public void addChange(@Nullable android.window.TaskFragmentTransaction.Change);
@@ -4284,8 +4290,8 @@
method @Nullable public android.os.IBinder getActivityToken();
method @NonNull public android.os.Bundle getErrorBundle();
method @Nullable public android.os.IBinder getErrorCallbackToken();
- method @Nullable public android.content.res.Configuration getTaskConfiguration();
method @Nullable public android.window.TaskFragmentInfo getTaskFragmentInfo();
+ method @Nullable public android.window.TaskFragmentParentInfo getTaskFragmentParentInfo();
method @Nullable public android.os.IBinder getTaskFragmentToken();
method public int getTaskId();
method public int getType();
@@ -4293,7 +4299,6 @@
method @NonNull public android.window.TaskFragmentTransaction.Change setActivityToken(@NonNull android.os.IBinder);
method @NonNull public android.window.TaskFragmentTransaction.Change setErrorBundle(@NonNull android.os.Bundle);
method @NonNull public android.window.TaskFragmentTransaction.Change setErrorCallbackToken(@Nullable android.os.IBinder);
- method @NonNull public android.window.TaskFragmentTransaction.Change setTaskConfiguration(@NonNull android.content.res.Configuration);
method @NonNull public android.window.TaskFragmentTransaction.Change setTaskFragmentInfo(@NonNull android.window.TaskFragmentInfo);
method @NonNull public android.window.TaskFragmentTransaction.Change setTaskFragmentToken(@NonNull android.os.IBinder);
method @NonNull public android.window.TaskFragmentTransaction.Change setTaskId(int);
diff --git a/core/java/android/app/servertransaction/ClientTransactionListenerController.java b/core/java/android/app/servertransaction/ClientTransactionListenerController.java
index cda2867..9b53461 100644
--- a/core/java/android/app/servertransaction/ClientTransactionListenerController.java
+++ b/core/java/android/app/servertransaction/ClientTransactionListenerController.java
@@ -33,11 +33,13 @@
import android.os.IBinder;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.window.ActivityWindowInfo;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.concurrent.RejectedExecutionException;
import java.util.function.BiConsumer;
/**
@@ -47,6 +49,8 @@
*/
public class ClientTransactionListenerController {
+ private static final String TAG = "ClientTransactionListenerController";
+
private static ClientTransactionListenerController sController;
private final Object mLock = new Object();
@@ -179,10 +183,14 @@
}
// Dispatch the display changed callbacks.
- final int displayCount = configUpdatedDisplayIds.size();
- for (int i = 0; i < displayCount; i++) {
- final int displayId = configUpdatedDisplayIds.valueAt(i);
- onDisplayChanged(displayId);
+ try {
+ final int displayCount = configUpdatedDisplayIds.size();
+ for (int i = 0; i < displayCount; i++) {
+ final int displayId = configUpdatedDisplayIds.valueAt(i);
+ onDisplayChanged(displayId);
+ }
+ } catch (RejectedExecutionException e) {
+ Log.w(TAG, "Failed to notify DisplayListener because the Handler is shutting down");
}
}
@@ -222,7 +230,11 @@
}
if (changedDisplayId != INVALID_DISPLAY) {
- onDisplayChanged(changedDisplayId);
+ try {
+ onDisplayChanged(changedDisplayId);
+ } catch (RejectedExecutionException e) {
+ Log.w(TAG, "Failed to notify DisplayListener because the Handler is shutting down");
+ }
}
}
@@ -235,9 +247,11 @@
/**
* Called when receives a {@link Configuration} changed event that is updating display-related
* window configuration.
+ *
+ * @throws RejectedExecutionException if the display listener handler is closing.
*/
@VisibleForTesting
- public void onDisplayChanged(int displayId) {
+ public void onDisplayChanged(int displayId) throws RejectedExecutionException {
mDisplayManager.handleDisplayChangeFromWindowManager(displayId);
}
}
diff --git a/core/java/android/hardware/usb/DeviceFilter.java b/core/java/android/hardware/usb/DeviceFilter.java
index 66b0a42..3a271b4 100644
--- a/core/java/android/hardware/usb/DeviceFilter.java
+++ b/core/java/android/hardware/usb/DeviceFilter.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.hardware.usb.flags.Flags;
import android.service.usb.UsbDeviceFilterProto;
import android.util.Slog;
@@ -57,9 +58,12 @@
public final String mProductName;
// USB device serial number string (or null for unspecified)
public final String mSerialNumber;
+ // USB interface name (or null for unspecified). This will be used when matching devices using
+ // the available interfaces.
+ public final String mInterfaceName;
public DeviceFilter(int vid, int pid, int clasz, int subclass, int protocol,
- String manufacturer, String product, String serialnum) {
+ String manufacturer, String product, String serialnum, String interfaceName) {
mVendorId = vid;
mProductId = pid;
mClass = clasz;
@@ -68,6 +72,7 @@
mManufacturerName = manufacturer;
mProductName = product;
mSerialNumber = serialnum;
+ mInterfaceName = interfaceName;
}
public DeviceFilter(UsbDevice device) {
@@ -79,6 +84,7 @@
mManufacturerName = device.getManufacturerName();
mProductName = device.getProductName();
mSerialNumber = device.getSerialNumber();
+ mInterfaceName = null;
}
public DeviceFilter(@NonNull DeviceFilter filter) {
@@ -90,6 +96,7 @@
mManufacturerName = filter.mManufacturerName;
mProductName = filter.mProductName;
mSerialNumber = filter.mSerialNumber;
+ mInterfaceName = filter.mInterfaceName;
}
public static DeviceFilter read(XmlPullParser parser)
@@ -102,7 +109,7 @@
String manufacturerName = null;
String productName = null;
String serialNumber = null;
-
+ String interfaceName = null;
int count = parser.getAttributeCount();
for (int i = 0; i < count; i++) {
String name = parser.getAttributeName(i);
@@ -114,6 +121,8 @@
productName = value;
} else if ("serial-number".equals(name)) {
serialNumber = value;
+ } else if ("interface-name".equals(name)) {
+ interfaceName = value;
} else {
int intValue;
int radix = 10;
@@ -144,7 +153,7 @@
}
return new DeviceFilter(vendorId, productId,
deviceClass, deviceSubclass, deviceProtocol,
- manufacturerName, productName, serialNumber);
+ manufacturerName, productName, serialNumber, interfaceName);
}
public void write(XmlSerializer serializer) throws IOException {
@@ -173,13 +182,25 @@
if (mSerialNumber != null) {
serializer.attribute(null, "serial-number", mSerialNumber);
}
+ if (mInterfaceName != null) {
+ serializer.attribute(null, "interface-name", mInterfaceName);
+ }
serializer.endTag(null, "usb-device");
}
- private boolean matches(int clasz, int subclass, int protocol) {
- return ((mClass == -1 || clasz == mClass) &&
- (mSubclass == -1 || subclass == mSubclass) &&
- (mProtocol == -1 || protocol == mProtocol));
+ private boolean matches(int usbClass, int subclass, int protocol) {
+ return ((mClass == -1 || usbClass == mClass)
+ && (mSubclass == -1 || subclass == mSubclass)
+ && (mProtocol == -1 || protocol == mProtocol));
+ }
+
+ private boolean matches(int usbClass, int subclass, int protocol, String interfaceName) {
+ if (Flags.enableInterfaceNameDeviceFilter()) {
+ return matches(usbClass, subclass, protocol)
+ && (mInterfaceName == null || mInterfaceName.equals(interfaceName));
+ } else {
+ return matches(usbClass, subclass, protocol);
+ }
}
public boolean matches(UsbDevice device) {
@@ -204,7 +225,7 @@
for (int i = 0; i < count; i++) {
UsbInterface intf = device.getInterface(i);
if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(),
- intf.getInterfaceProtocol())) return true;
+ intf.getInterfaceProtocol(), intf.getName())) return true;
}
return false;
@@ -320,11 +341,12 @@
@Override
public String toString() {
- return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId +
- ",mClass=" + mClass + ",mSubclass=" + mSubclass +
- ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName +
- ",mProductName=" + mProductName + ",mSerialNumber=" + mSerialNumber +
- "]";
+ return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId
+ + ",mClass=" + mClass + ",mSubclass=" + mSubclass
+ + ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName
+ + ",mProductName=" + mProductName + ",mSerialNumber=" + mSerialNumber
+ + ",mInterfaceName=" + mInterfaceName
+ + "]";
}
/**
diff --git a/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig b/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig
index 94df160..40e5ffb 100644
--- a/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig
+++ b/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig
@@ -16,3 +16,11 @@
description: "Feature flag for the api to check if a port supports mode change"
bug: "323470419"
}
+
+flag {
+ name: "enable_interface_name_device_filter"
+ is_exported: true
+ namespace: "usb"
+ description: "Feature flag to enable interface name as a parameter for device filter"
+ bug: "312828160"
+}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1df851a..0715474 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -921,15 +921,6 @@
private String mFrameRateCategoryView;
/**
- * The resolved pointer icon type requested by this window.
- * A null value indicates the resolved pointer icon has not yet been calculated.
- */
- // TODO(b/293587049): Remove pointer icon tracking by type when refactor is complete.
- @Nullable
- private Integer mPointerIconType = null;
- private PointerIcon mCustomPointerIcon = null;
-
- /**
* The resolved pointer icon requested by this window.
* A null value indicates the resolved pointer icon has not yet been calculated.
*/
@@ -6430,7 +6421,6 @@
private static final int MSG_SYNTHESIZE_INPUT_EVENT = 24;
private static final int MSG_DISPATCH_WINDOW_SHOWN = 25;
private static final int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
- private static final int MSG_UPDATE_POINTER_ICON = 27;
private static final int MSG_POINTER_CAPTURE_CHANGED = 28;
private static final int MSG_INSETS_CONTROL_CHANGED = 29;
private static final int MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED = 30;
@@ -6495,8 +6485,6 @@
return "MSG_SYNTHESIZE_INPUT_EVENT";
case MSG_DISPATCH_WINDOW_SHOWN:
return "MSG_DISPATCH_WINDOW_SHOWN";
- case MSG_UPDATE_POINTER_ICON:
- return "MSG_UPDATE_POINTER_ICON";
case MSG_POINTER_CAPTURE_CHANGED:
return "MSG_POINTER_CAPTURE_CHANGED";
case MSG_INSETS_CONTROL_CHANGED:
@@ -6747,10 +6735,6 @@
final int deviceId = msg.arg1;
handleRequestKeyboardShortcuts(receiver, deviceId);
} break;
- case MSG_UPDATE_POINTER_ICON: {
- MotionEvent event = (MotionEvent) msg.obj;
- resetPointerIcon(event);
- } break;
case MSG_POINTER_CAPTURE_CHANGED: {
final boolean hasCapture = msg.arg1 != 0;
handlePointerCaptureChanged(hasCapture);
@@ -7836,14 +7820,12 @@
|| action == MotionEvent.ACTION_HOVER_EXIT) {
// Other apps or the window manager may change the icon type outside of
// this app, therefore the icon type has to be reset on enter/exit event.
- mPointerIconType = null;
mResolvedPointerIcon = null;
}
if (action != MotionEvent.ACTION_HOVER_EXIT) {
// Resolve the pointer icon
if (!updatePointerIcon(event) && action == MotionEvent.ACTION_HOVER_MOVE) {
- mPointerIconType = null;
mResolvedPointerIcon = null;
}
}
@@ -7906,12 +7888,6 @@
return mAttachInfo.mHandlingPointerEvent;
}
- private void resetPointerIcon(MotionEvent event) {
- mPointerIconType = null;
- mResolvedPointerIcon = null;
- updatePointerIcon(event);
- }
-
/**
* If there is pointer that is showing a PointerIcon in this window, refresh the icon for that
diff --git a/core/java/android/window/TaskFragmentParentInfo.java b/core/java/android/window/TaskFragmentParentInfo.java
index a77c234..1555416 100644
--- a/core/java/android/window/TaskFragmentParentInfo.java
+++ b/core/java/android/window/TaskFragmentParentInfo.java
@@ -18,6 +18,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.TestApi;
import android.app.WindowConfiguration;
import android.content.res.Configuration;
import android.os.Parcel;
@@ -27,10 +29,13 @@
import java.util.Objects;
/**
- * The information about the parent Task of a particular TaskFragment
+ * The information about the parent Task of a particular TaskFragment.
+ *
* @hide
*/
-public class TaskFragmentParentInfo implements Parcelable {
+@SuppressLint("UnflaggedApi") // @TestApi to replace legacy usages.
+@TestApi
+public final class TaskFragmentParentInfo implements Parcelable {
@NonNull
private final Configuration mConfiguration = new Configuration();
@@ -42,6 +47,7 @@
@Nullable private final SurfaceControl mDecorSurface;
+ /** @hide */
public TaskFragmentParentInfo(@NonNull Configuration configuration, int displayId,
boolean visible, boolean hasDirectActivity, @Nullable SurfaceControl decorSurface) {
mConfiguration.setTo(configuration);
@@ -51,6 +57,7 @@
mDecorSurface = decorSurface;
}
+ /** @hide */
public TaskFragmentParentInfo(@NonNull TaskFragmentParentInfo info) {
mConfiguration.setTo(info.getConfiguration());
mDisplayId = info.mDisplayId;
@@ -59,7 +66,11 @@
mDecorSurface = info.mDecorSurface;
}
- /** The {@link Configuration} of the parent Task */
+ /**
+ * The {@link Configuration} of the parent Task
+ *
+ * @hide
+ */
@NonNull
public Configuration getConfiguration() {
return mConfiguration;
@@ -68,19 +79,27 @@
/**
* The display ID of the parent Task. {@link android.view.Display#INVALID_DISPLAY} means the
* Task is detached from previously associated display.
+ *
+ * @hide
*/
public int getDisplayId() {
return mDisplayId;
}
- /** Whether the parent Task is visible or not */
+ /**
+ * Whether the parent Task is visible or not
+ *
+ * @hide
+ */
public boolean isVisible() {
return mVisible;
}
/**
* Whether the parent Task has any direct child activity, which is not embedded in any
- * TaskFragment, or not
+ * TaskFragment, or not.
+ *
+ * @hide
*/
public boolean hasDirectActivity() {
return mHasDirectActivity;
@@ -93,6 +112,8 @@
* {@link com.android.server.wm.WindowOrganizerController#configurationsAreEqualForOrganizer(
* Configuration, Configuration)} to determine if this {@link TaskFragmentParentInfo} should
* be dispatched to the client.
+ *
+ * @hide
*/
public boolean equalsForTaskFragmentOrganizer(@Nullable TaskFragmentParentInfo that) {
if (that == null) {
@@ -103,6 +124,7 @@
&& mDecorSurface == that.mDecorSurface;
}
+ /** @hide */
@Nullable
public SurfaceControl getDecorSurface() {
return mDecorSurface;
@@ -156,6 +178,7 @@
return result;
}
+ @SuppressLint("UnflaggedApi") // @TestApi to replace legacy usages.
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
mConfiguration.writeToParcel(dest, flags);
@@ -173,6 +196,8 @@
mDecorSurface = in.readTypedObject(SurfaceControl.CREATOR);
}
+ @SuppressLint("UnflaggedApi") // @TestApi to replace legacy usages.
+ @NonNull
public static final Creator<TaskFragmentParentInfo> CREATOR =
new Creator<TaskFragmentParentInfo>() {
@Override
@@ -186,6 +211,7 @@
}
};
+ @SuppressLint("UnflaggedApi") // @TestApi to replace legacy usages.
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/window/TaskFragmentTransaction.java b/core/java/android/window/TaskFragmentTransaction.java
index 4dada10..32e3f5a 100644
--- a/core/java/android/window/TaskFragmentTransaction.java
+++ b/core/java/android/window/TaskFragmentTransaction.java
@@ -24,7 +24,6 @@
import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.content.Intent;
-import android.content.res.Configuration;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -248,13 +247,6 @@
return this;
}
- // TODO(b/241043377): Keep this API to prevent @TestApi changes. Remove in the next release.
- /** Configuration of the parent Task. */
- @NonNull
- public Change setTaskConfiguration(@NonNull Configuration configuration) {
- return this;
- }
-
/**
* If the {@link #TYPE_TASK_FRAGMENT_ERROR} is from a {@link WindowContainerTransaction}
* from the {@link TaskFragmentOrganizer}, it may come with an error callback token to
@@ -299,12 +291,11 @@
return this;
}
- // TODO(b/241043377): Hide this API to prevent @TestApi changes. Remove in the next release.
/**
* Sets info of the parent Task of the embedded TaskFragment.
* @see TaskFragmentParentInfo
*
- * @hide pending unhide
+ * @hide
*/
@NonNull
public Change setTaskFragmentParentInfo(@NonNull TaskFragmentParentInfo info) {
@@ -338,12 +329,6 @@
return mTaskId;
}
- // TODO(b/241043377): Keep this API to prevent @TestApi changes. Remove in the next release.
- @Nullable
- public Configuration getTaskConfiguration() {
- return mTaskFragmentParentInfo.getConfiguration();
- }
-
@Nullable
public IBinder getErrorCallbackToken() {
return mErrorCallbackToken;
@@ -365,8 +350,10 @@
return mActivityToken;
}
- // TODO(b/241043377): Hide this API to prevent @TestApi changes. Remove in the next release.
- /** @hide pending unhide */
+ /**
+ * Obtains the {@link TaskFragmentParentInfo} for this transaction.
+ */
+ @SuppressLint("UnflaggedApi") // @TestApi to replace legacy usages.
@Nullable
public TaskFragmentParentInfo getTaskFragmentParentInfo() {
return mTaskFragmentParentInfo;
diff --git a/core/res/res/values/config_battery_stats.xml b/core/res/res/values/config_battery_stats.xml
index 8d97362..80cf088 100644
--- a/core/res/res/values/config_battery_stats.xml
+++ b/core/res/res/values/config_battery_stats.xml
@@ -27,16 +27,18 @@
<!-- Whether to reset Battery Stats on unplug if the battery was significantly charged -->
<bool name="config_batteryStatsResetOnUnplugAfterSignificantCharge">true</bool>
- <!-- CPU power stats collection throttle period in milliseconds. Since power stats collection
- is a relatively expensive operation, this throttle period may need to be adjusted for low-power
- devices-->
- <integer name="config_defaultPowerStatsThrottlePeriodCpu">60000</integer>
+ <!-- Power stats collection throttle periods in milliseconds. Since power stats collection
+ is a relatively expensive operation, these throttle period may need to be adjusted for low-power
+ devices.
- <!-- Mobile Radio power stats collection throttle period in milliseconds. -->
- <integer name="config_defaultPowerStatsThrottlePeriodMobileRadio">3600000</integer>
-
- <!-- Mobile Radio power stats collection throttle period in milliseconds. -->
- <integer name="config_defaultPowerStatsThrottlePeriodWifi">3600000</integer>
+ The syntax of this config string is as follows:
+ <pre>
+ power-component-name1:throttle-period-millis1 power-component-name2:throttle-period-ms2 ...
+ </pre>
+ Use "*" for the power-component-name to represent the default for all power components
+ not mentioned by name.
+ -->
+ <string name="config_powerStatsThrottlePeriods">cpu:60000 *:300000</string>
<!-- PowerStats aggregation period in milliseconds. This is the interval at which the power
stats aggregation procedure is performed and the results stored in PowerStatsStore. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a9d03f5..acd3b37 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -5243,9 +5243,7 @@
<java-symbol type="bool" name="config_batteryStatsResetOnUnplugHighBatteryLevel" />
<java-symbol type="bool" name="config_batteryStatsResetOnUnplugAfterSignificantCharge" />
- <java-symbol type="integer" name="config_defaultPowerStatsThrottlePeriodCpu" />
- <java-symbol type="integer" name="config_defaultPowerStatsThrottlePeriodMobileRadio" />
- <java-symbol type="integer" name="config_defaultPowerStatsThrottlePeriodWifi" />
+ <java-symbol type="string" name="config_powerStatsThrottlePeriods" />
<java-symbol type="integer" name="config_powerStatsAggregationPeriod" />
<java-symbol type="integer" name="config_aggregatedPowerStatsSpanDuration" />
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
index b6f4429..ee1d1e1 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
@@ -29,6 +29,7 @@
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -65,6 +66,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.concurrent.RejectedExecutionException;
import java.util.function.BiConsumer;
/**
@@ -221,4 +223,17 @@
123 /* newDisplayId */, true /* shouldReportConfigChange*/);
inOrder.verify(mController).onContextConfigurationPostChanged(context);
}
+
+ @Test
+ public void testDisplayListenerHandlerClosed() {
+ doReturn(123).when(mActivity).getDisplayId();
+ doThrow(new RejectedExecutionException()).when(mController).onDisplayChanged(123);
+
+ mController.onContextConfigurationPreChanged(mActivity);
+ mConfiguration.windowConfiguration.setMaxBounds(new Rect(0, 0, 100, 200));
+ mController.onContextConfigurationPostChanged(mActivity);
+
+ // No crash
+ verify(mController).onDisplayChanged(123);
+ }
}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java
index dcd4062..785e30d 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java
@@ -69,8 +69,12 @@
/** Returns {@code true} if the transition is opening or closing mode. */
public static boolean isOpenOrCloseMode(@TransitionInfo.TransitionMode int mode) {
- return mode == TRANSIT_OPEN || mode == TRANSIT_CLOSE
- || mode == TRANSIT_TO_FRONT || mode == TRANSIT_TO_BACK;
+ return isOpeningMode(mode) || mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK;
+ }
+
+ /** Returns {@code true} if the transition is opening mode. */
+ public static boolean isOpeningMode(@TransitionInfo.TransitionMode int mode) {
+ return mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT;
}
/** Returns {@code true} if the transition has a display change. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index e885262..e1657f9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -854,7 +854,8 @@
mPipUiEventLoggerLogger.log(uiEventEnum);
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
- "onTaskAppeared: %s, state=%s", mTaskInfo.topActivity, mPipTransitionState);
+ "onTaskAppeared: %s, state=%s, taskId=%s", mTaskInfo.topActivity,
+ mPipTransitionState, mTaskInfo.taskId);
if (mPipTransitionState.getInSwipePipToHomeTransition()) {
if (!mWaitForFixedRotation) {
onEndOfSwipePipToHomeTransition();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index b10176d..8e97068 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -47,6 +47,7 @@
import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
import static com.android.wm.shell.shared.TransitionUtil.isClosingType;
+import static com.android.wm.shell.shared.TransitionUtil.isOpeningMode;
import static com.android.wm.shell.shared.TransitionUtil.isOpeningType;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
@@ -67,6 +68,7 @@
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_UNKNOWN;
import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
+import static com.android.wm.shell.transition.MixedTransitionHelper.getPipReplacingChange;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
@@ -2836,7 +2838,7 @@
mSplitLayout.setFreezeDividerWindow(false);
final StageChangeRecord record = new StageChangeRecord();
final int transitType = info.getType();
- boolean hasEnteringPip = false;
+ TransitionInfo.Change pipChange = null;
for (int iC = 0; iC < info.getChanges().size(); ++iC) {
final TransitionInfo.Change change = info.getChanges().get(iC);
if (change.getMode() == TRANSIT_CHANGE
@@ -2847,7 +2849,7 @@
}
if (mMixedHandler.isEnteringPip(change, transitType)) {
- hasEnteringPip = true;
+ pipChange = change;
}
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
@@ -2899,9 +2901,19 @@
}
}
- if (hasEnteringPip) {
+ if (pipChange != null) {
+ TransitionInfo.Change pipReplacingChange = getPipReplacingChange(info, pipChange,
+ mMainStage.mRootTaskInfo.taskId, mSideStage.mRootTaskInfo.taskId,
+ getSplitItemStage(pipChange.getLastParent()));
+ if (pipReplacingChange != null) {
+ // Set an enter transition for when startAnimation gets called again
+ mSplitTransitions.setEnterTransition(transition, /*remoteTransition*/ null,
+ TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, /*resizeAnim*/ false);
+ }
+
mMixedHandler.animatePendingEnterPipFromSplit(transition, info,
- startTransaction, finishTransaction, finishCallback);
+ startTransaction, finishTransaction, finishCallback,
+ pipReplacingChange != null);
notifySplitAnimationFinished();
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 1e305c5..f77c80d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -177,9 +177,11 @@
@Override
@CallSuper
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskAppeared: task=%d taskParent=%d rootTask=%d",
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskAppeared: taskId=%d taskParent=%d rootTask=%d "
+ + "taskActivity=%s",
taskInfo.taskId, taskInfo.parentTaskId,
- mRootTaskInfo != null ? mRootTaskInfo.taskId : -1);
+ mRootTaskInfo != null ? mRootTaskInfo.taskId : -1,
+ taskInfo.baseActivity);
if (mRootTaskInfo == null) {
mRootLeash = leash;
mRootTaskInfo = taskInfo;
@@ -213,6 +215,8 @@
@Override
@CallSuper
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskInfoChanged: taskId=%d taskAct=%s",
+ taskInfo.taskId, taskInfo.baseActivity);
mWindowDecorViewModel.ifPresent(viewModel -> viewModel.onTaskInfoChanged(taskInfo));
if (mRootTaskInfo.taskId == taskInfo.taskId) {
// Inflates split decor view only when the root task is visible.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 968b27b..bcacecb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -77,6 +77,7 @@
private ActivityEmbeddingController mActivityEmbeddingController;
abstract static class MixedTransition {
+ /** Entering Pip from split, breaks split. */
static final int TYPE_ENTER_PIP_FROM_SPLIT = 1;
/** Both the display and split-state (enter/exit) is changing */
@@ -103,6 +104,9 @@
/** Enter pip from one of the Activity Embedding windows. */
static final int TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING = 9;
+ /** Entering Pip from split, but replace the Pip stage instead of breaking split. */
+ static final int TYPE_ENTER_PIP_REPLACE_FROM_SPLIT = 10;
+
/** The default animation for this mixed transition. */
static final int ANIM_TYPE_DEFAULT = 0;
@@ -484,9 +488,11 @@
// TODO(b/287704263): Remove when split/mixed are reversed.
public boolean animatePendingEnterPipFromSplit(IBinder transition, TransitionInfo info,
SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
- Transitions.TransitionFinishCallback finishCallback) {
- final MixedTransition mixed = createDefaultMixedTransition(
- MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT, transition);
+ Transitions.TransitionFinishCallback finishCallback, boolean replacingPip) {
+ int type = replacingPip
+ ? MixedTransition.TYPE_ENTER_PIP_REPLACE_FROM_SPLIT
+ : MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT;
+ final MixedTransition mixed = createDefaultMixedTransition(type, transition);
mActiveTransitions.add(mixed);
Transitions.TransitionFinishCallback callback = wct -> {
mActiveTransitions.remove(mixed);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java
index b028bd6..0ada749 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java
@@ -76,7 +76,12 @@
info, startTransaction, finishTransaction, finishCallback);
case TYPE_ENTER_PIP_FROM_SPLIT ->
animateEnterPipFromSplit(this, info, startTransaction, finishTransaction,
- finishCallback, mPlayer, mMixedHandler, mPipHandler, mSplitHandler);
+ finishCallback, mPlayer, mMixedHandler, mPipHandler, mSplitHandler,
+ /*replacingPip*/ false);
+ case TYPE_ENTER_PIP_REPLACE_FROM_SPLIT ->
+ animateEnterPipFromSplit(this, info, startTransaction, finishTransaction,
+ finishCallback, mPlayer, mMixedHandler, mPipHandler, mSplitHandler,
+ /*replacingPip*/ true);
case TYPE_KEYGUARD ->
animateKeyguard(this, info, startTransaction, finishTransaction, finishCallback,
mKeyguardHandler, mPipHandler);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java
index ffc0b76..e8b01b5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java
@@ -23,11 +23,15 @@
import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
+import static com.android.wm.shell.shared.TransitionUtil.isOpeningMode;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
import static com.android.wm.shell.transition.DefaultMixedHandler.subCopy;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
@@ -45,7 +49,8 @@
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback,
@NonNull Transitions player, @NonNull MixedTransitionHandler mixedHandler,
- @NonNull PipTransitionController pipHandler, @NonNull StageCoordinator splitHandler) {
+ @NonNull PipTransitionController pipHandler, @NonNull StageCoordinator splitHandler,
+ boolean replacingPip) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animating a mixed transition for "
+ "entering PIP while Split-Screen is foreground.");
TransitionInfo.Change pipChange = null;
@@ -99,7 +104,7 @@
// we need a separate one to send over to launcher.
SurfaceControl.Transaction otherStartT = new SurfaceControl.Transaction();
@SplitScreen.StageType int topStageToKeep = STAGE_TYPE_UNDEFINED;
- if (splitHandler.isSplitScreenVisible()) {
+ if (splitHandler.isSplitScreenVisible() && !replacingPip) {
// The non-going home case, we could be pip-ing one of the split stages and keep
// showing the other
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
@@ -115,11 +120,12 @@
break;
}
}
+
+ // Let split update internal state for dismiss.
+ splitHandler.prepareDismissAnimation(topStageToKeep,
+ EXIT_REASON_CHILD_TASK_ENTER_PIP, everythingElse, otherStartT,
+ finishTransaction);
}
- // Let split update internal state for dismiss.
- splitHandler.prepareDismissAnimation(topStageToKeep,
- EXIT_REASON_CHILD_TASK_ENTER_PIP, everythingElse, otherStartT,
- finishTransaction);
// We are trying to accommodate launcher's close animation which can't handle the
// divider-bar, so if split-handler is closing the divider-bar, just hide it and
@@ -152,6 +158,44 @@
return true;
}
+ /**
+ * Check to see if we're only closing split to enter pip or if we're replacing pip with
+ * another task. If we are replacing, this will return the change for the task we are replacing
+ * pip with
+ *
+ * @param info Any number of changes
+ * @param pipChange TransitionInfo.Change indicating the task that is being pipped
+ * @param splitMainStageRootId MainStage's rootTaskInfo's id
+ * @param splitSideStageRootId SideStage's rootTaskInfo's id
+ * @param lastPipSplitStage The last stage that {@param pipChange} was in
+ * @return The change from {@param info} that is replacing the {@param pipChange}, {@code null}
+ * otherwise
+ */
+ @Nullable
+ public static TransitionInfo.Change getPipReplacingChange(TransitionInfo info,
+ TransitionInfo.Change pipChange, int splitMainStageRootId, int splitSideStageRootId,
+ @SplitScreen.StageType int lastPipSplitStage) {
+ int lastPipParentTask = -1;
+ if (lastPipSplitStage == STAGE_TYPE_MAIN) {
+ lastPipParentTask = splitMainStageRootId;
+ } else if (lastPipSplitStage == STAGE_TYPE_SIDE) {
+ lastPipParentTask = splitSideStageRootId;
+ }
+
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ TransitionInfo.Change change = info.getChanges().get(i);
+ if (change == pipChange || !isOpeningMode(change.getMode())) {
+ // Ignore the change/task that's going into Pip or not opening
+ continue;
+ }
+
+ if (change.getTaskInfo().parentTaskId == lastPipParentTask) {
+ return change;
+ }
+ }
+ return null;
+ }
+
private static boolean isHomeOpening(@NonNull TransitionInfo.Change change) {
return change.getTaskInfo() != null
&& change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
index d6e64cf..9fc6702 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
@@ -142,7 +142,8 @@
&& mSplitHandler.getSplitItemPosition(change.getLastParent())
!= SPLIT_POSITION_UNDEFINED) {
return animateEnterPipFromSplit(this, info, startTransaction, finishTransaction,
- finishCallback, mPlayer, mMixedHandler, mPipHandler, mSplitHandler);
+ finishCallback, mPlayer, mMixedHandler, mPipHandler, mSplitHandler,
+ /*replacingPip*/ false);
}
}
diff --git a/packages/SettingsLib/SettingsTheme/res/color-v35/settingslib_preference_bg_color.xml b/packages/SettingsLib/SettingsTheme/res/color-v35/settingslib_preference_bg_color.xml
index 4ced9f2..cece966 100644
--- a/packages/SettingsLib/SettingsTheme/res/color-v35/settingslib_preference_bg_color.xml
+++ b/packages/SettingsLib/SettingsTheme/res/color-v35/settingslib_preference_bg_color.xml
@@ -16,8 +16,8 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true" android:color="@color/settingslib_materialColorSecondaryContainer"/>
- <item android:state_selected="true" android:color="@color/settingslib_materialColorSecondaryContainer"/>
- <item android:state_activated="true" android:color="@color/settingslib_materialColorSecondaryContainer"/>
- <item android:color="@color/settingslib_materialColorSurfaceContainerHighest"/> <!-- not selected -->
+ <item android:state_pressed="true" android:color="@color/settingslib_materialColorSurfaceContainerHigh"/>
+ <item android:state_selected="true" android:color="@color/settingslib_materialColorSurfaceContainerHigh"/>
+ <item android:state_activated="true" android:color="@color/settingslib_materialColorSurfaceContainerHigh"/>
+ <item android:color="@color/settingslib_materialColorSurfaceBright"/> <!-- not selected -->
</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background.xml
index 285ab73..eba9c2c 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background.xml
@@ -19,12 +19,12 @@
<item
android:left="?android:attr/listPreferredItemPaddingStart"
android:right="?android:attr/listPreferredItemPaddingEnd"
- android:top="1dp">
+ android:top="2dp">
<shape android:shape="rectangle">
<solid
android:color="@color/settingslib_preference_bg_color" />
<corners
- android:radius="?android:attr/dialogCornerRadius" />
+ android:radius="@dimen/settingslib_preference_corner_radius" />
</shape>
</item>
</layer-list>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom.xml
index e417307..5c60f37 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom.xml
@@ -19,15 +19,15 @@
<item
android:left="?android:attr/listPreferredItemPaddingStart"
android:right="?android:attr/listPreferredItemPaddingEnd"
- android:top="1dp">
+ android:top="2dp">
<shape android:shape="rectangle">
<solid
android:color="@color/settingslib_preference_bg_color" />
<corners
- android:topLeftRadius="0dp"
- android:bottomLeftRadius="?android:attr/dialogCornerRadius"
- android:topRightRadius="0dp"
- android:bottomRightRadius="?android:attr/dialogCornerRadius" />
+ android:topLeftRadius="4dp"
+ android:bottomLeftRadius="@dimen/settingslib_preference_corner_radius"
+ android:topRightRadius="4dp"
+ android:bottomRightRadius="@dimen/settingslib_preference_corner_radius" />
</shape>
</item>
</layer-list>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom_selected.xml
new file mode 100644
index 0000000..de64efd
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_bottom_selected.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:left="?android:attr/listPreferredItemPaddingStart"
+ android:right="?android:attr/listPreferredItemPaddingEnd"
+ android:top="2dp">
+ <shape android:shape="rectangle">
+ <solid
+ android:color="@color/settingslib_materialColorSurfaceContainerHigh" />
+ <corners
+ android:topLeftRadius="4dp"
+ android:bottomLeftRadius="@dimen/settingslib_preference_corner_radius"
+ android:topRightRadius="4dp"
+ android:bottomRightRadius="@dimen/settingslib_preference_corner_radius" />
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center.xml
index e964657..dd70f4f 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center.xml
@@ -19,12 +19,12 @@
<item
android:left="?android:attr/listPreferredItemPaddingStart"
android:right="?android:attr/listPreferredItemPaddingEnd"
- android:top="1dp">
+ android:top="2dp">
<shape android:shape="rectangle">
<solid
android:color="@color/settingslib_preference_bg_color" />
<corners
- android:radius="1dp" />
+ android:radius="4dp" />
</shape>
</item>
</layer-list>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center_selected.xml
new file mode 100644
index 0000000..fffc6c8
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_center_selected.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:left="?android:attr/listPreferredItemPaddingStart"
+ android:right="?android:attr/listPreferredItemPaddingEnd"
+ android:top="2dp">
+ <shape android:shape="rectangle">
+ <solid
+ android:color="@color/settingslib_materialColorSurfaceContainerHigh" />
+ <corners
+ android:radius="4dp" />
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_selected.xml
new file mode 100644
index 0000000..f83e3b1
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_selected.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:left="?android:attr/listPreferredItemPaddingStart"
+ android:right="?android:attr/listPreferredItemPaddingEnd"
+ android:top="2dp">
+ <shape android:shape="rectangle">
+ <solid
+ android:color="@color/settingslib_materialColorSurfaceContainerHigh" />
+ <corners
+ android:radius="@dimen/settingslib_preference_corner_radius" />
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top.xml
index a9d69c2..ab79d18 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top.xml
@@ -19,15 +19,15 @@
<item
android:left="?android:attr/listPreferredItemPaddingStart"
android:right="?android:attr/listPreferredItemPaddingEnd"
- android:top="1dp">
+ android:top="2dp">
<shape android:shape="rectangle">
<solid
android:color="@color/settingslib_preference_bg_color" />
<corners
- android:topLeftRadius="?android:attr/dialogCornerRadius"
- android:bottomLeftRadius="0dp"
- android:topRightRadius="?android:attr/dialogCornerRadius"
- android:bottomRightRadius="0dp" />
+ android:topLeftRadius="@dimen/settingslib_preference_corner_radius"
+ android:bottomLeftRadius="4dp"
+ android:topRightRadius="@dimen/settingslib_preference_corner_radius"
+ android:bottomRightRadius="4dp" />
</shape>
</item>
</layer-list>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top_selected.xml
new file mode 100644
index 0000000..112ec73
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_round_background_top_selected.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:left="?android:attr/listPreferredItemPaddingStart"
+ android:right="?android:attr/listPreferredItemPaddingEnd"
+ android:top="2dp">
+ <shape android:shape="rectangle">
+ <solid
+ android:color="@color/settingslib_materialColorSurfaceContainerHigh" />
+ <corners
+ android:topLeftRadius="@dimen/settingslib_preference_corner_radius"
+ android:bottomLeftRadius="4dp"
+ android:topRightRadius="@dimen/settingslib_preference_corner_radius"
+ android:bottomRightRadius="4dp" />
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values-v35/dimens.xml
new file mode 100644
index 0000000..d783956
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-v35/dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<resources>
+ <dimen name="settingslib_preference_corner_radius">20dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
index 6e9bde4..8276e18 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
@@ -29,36 +29,46 @@
import kotlinx.coroutines.flow.map
interface IAppOpsController {
- val mode: Flow<Int>
+ val modeFlow: Flow<Int>
val isAllowed: Flow<Boolean>
- get() = mode.map { it == MODE_ALLOWED }
+ get() = modeFlow.map { it == MODE_ALLOWED }
fun setAllowed(allowed: Boolean)
@Mode fun getMode(): Int
}
+data class AppOps(
+ val op: Int,
+ val modeForNotAllowed: Int = MODE_ERRORED,
+
+ /**
+ * Use AppOpsManager#setUidMode() instead of AppOpsManager#setMode() when set allowed.
+ *
+ * Security or privacy related app-ops should be set with setUidMode() instead of setMode().
+ */
+ val setModeByUid: Boolean = false,
+)
+
class AppOpsController(
context: Context,
private val app: ApplicationInfo,
- private val op: Int,
- private val modeForNotAllowed: Int = MODE_ERRORED,
- private val setModeByUid: Boolean = false,
+ private val appOps: AppOps,
) : IAppOpsController {
private val appOpsManager = context.appOpsManager
private val packageManager = context.packageManager
- override val mode = appOpsManager.opModeFlow(op, app)
+ override val modeFlow = appOpsManager.opModeFlow(appOps.op, app)
override fun setAllowed(allowed: Boolean) {
- val mode = if (allowed) MODE_ALLOWED else modeForNotAllowed
+ val mode = if (allowed) MODE_ALLOWED else appOps.modeForNotAllowed
- if (setModeByUid) {
- appOpsManager.setUidMode(op, app.uid, mode)
+ if (appOps.setModeByUid) {
+ appOpsManager.setUidMode(appOps.op, app.uid, mode)
} else {
- appOpsManager.setMode(op, app.uid, app.packageName, mode)
+ appOpsManager.setMode(appOps.op, app.uid, app.packageName, mode)
}
- val permission = AppOpsManager.opToPermission(op)
+ val permission = AppOpsManager.opToPermission(appOps.op)
if (permission != null) {
packageManager.updatePermissionFlags(permission, app.packageName,
PackageManager.FLAG_PERMISSION_USER_SET,
@@ -67,5 +77,6 @@
}
}
- @Mode override fun getMode(): Int = appOpsManager.getOpMode(op, app)
+ @Mode
+ override fun getMode(): Int = appOpsManager.getOpMode(appOps.op, app)
}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
index 5db5eae..37b1d73 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
@@ -23,6 +23,7 @@
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.settingslib.spa.framework.util.asyncMapItem
import com.android.settingslib.spa.framework.util.filterItem
+import com.android.settingslib.spaprivileged.model.app.AppOps
import com.android.settingslib.spaprivileged.model.app.AppOpsController
import com.android.settingslib.spaprivileged.model.app.AppRecord
import com.android.settingslib.spaprivileged.model.app.IAppOpsController
@@ -44,11 +45,11 @@
private val packageManagers: IPackageManagers = PackageManagers,
) : TogglePermissionAppListModel<AppOpPermissionRecord> {
- abstract val appOp: Int
+ abstract val appOps: AppOps
abstract val permission: String
override val enhancedConfirmationKey: String?
- get() = AppOpsManager.opToPublicName(appOp)
+ get() = AppOpsManager.opToPublicName(appOps.op)
/**
* When set, specifies the broader permission who trumps the [permission].
@@ -65,27 +66,12 @@
*/
open val permissionHasAppOpFlag: Boolean = true
- open val modeForNotAllowed: Int = AppOpsManager.MODE_ERRORED
-
- /**
- * Use AppOpsManager#setUidMode() instead of AppOpsManager#setMode() when set allowed.
- *
- * Security or privacy related app-ops should be set with setUidMode() instead of setMode().
- */
- open val setModeByUid = false
-
/** These not changeable packages will also be hidden from app list. */
private val notChangeablePackages =
setOf("android", "com.android.systemui", context.packageName)
private fun createAppOpsController(app: ApplicationInfo) =
- AppOpsController(
- context = context,
- app = app,
- op = appOp,
- setModeByUid = setModeByUid,
- modeForNotAllowed = modeForNotAllowed,
- )
+ AppOpsController(context, app, appOps)
private fun createRecord(
app: ApplicationInfo,
@@ -166,7 +152,7 @@
return { true }
}
- val mode = appOpsController.mode.collectAsStateWithLifecycle(initialValue = null)
+ val mode = appOpsController.modeFlow.collectAsStateWithLifecycle(initialValue = null)
return {
when (mode.value) {
null -> null
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
index 91bbd9f..74a7c14 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
@@ -27,16 +27,14 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spaprivileged.framework.common.appOpsManager
import com.google.common.truth.Truth.assertThat
-import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Spy
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
-import org.mockito.kotlin.any
-import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
@@ -44,28 +42,18 @@
class AppOpsControllerTest {
@get:Rule val mockito: MockitoRule = MockitoJUnit.rule()
- @Spy private val context: Context = ApplicationProvider.getApplicationContext()
+ private val appOpsManager = mock<AppOpsManager>()
- @Mock private lateinit var appOpsManager: AppOpsManager
+ private val packageManager = mock<PackageManager>()
- @Mock private lateinit var packageManager: PackageManager
-
- @Before
- fun setUp() {
- whenever(context.appOpsManager).thenReturn(appOpsManager)
- whenever(context.packageManager).thenReturn(packageManager)
- doNothing().whenever(packageManager)
- .updatePermissionFlags(any(), any(), any(), any(), any())
+ private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+ on { appOpsManager } doReturn appOpsManager
+ on { packageManager } doReturn packageManager
}
@Test
fun setAllowed_setToTrue() {
- val controller =
- AppOpsController(
- context = context,
- app = APP,
- op = OP,
- )
+ val controller = AppOpsController(context = context, app = APP, appOps = AppOps(OP))
controller.setAllowed(true)
@@ -74,12 +62,7 @@
@Test
fun setAllowed_setToFalse() {
- val controller =
- AppOpsController(
- context = context,
- app = APP,
- op = OP,
- )
+ val controller = AppOpsController(context = context, app = APP, appOps = AppOps(OP))
controller.setAllowed(false)
@@ -88,13 +71,11 @@
@Test
fun setAllowed_setToFalseWithModeForNotAllowed() {
- val controller =
- AppOpsController(
- context = context,
- app = APP,
- op = OP,
- modeForNotAllowed = MODE_IGNORED,
- )
+ val controller = AppOpsController(
+ context = context,
+ app = APP,
+ appOps = AppOps(op = OP, modeForNotAllowed = MODE_IGNORED),
+ )
controller.setAllowed(false)
@@ -103,13 +84,11 @@
@Test
fun setAllowed_setToTrueByUid() {
- val controller =
- AppOpsController(
- context = context,
- app = APP,
- op = OP,
- setModeByUid = true,
- )
+ val controller = AppOpsController(
+ context = context,
+ app = APP,
+ appOps = AppOps(op = OP, setModeByUid = true),
+ )
controller.setAllowed(true)
@@ -118,13 +97,11 @@
@Test
fun setAllowed_setToFalseByUid() {
- val controller =
- AppOpsController(
- context = context,
- app = APP,
- op = OP,
- setModeByUid = true,
- )
+ val controller = AppOpsController(
+ context = context,
+ app = APP,
+ appOps = AppOps(op = OP, setModeByUid = true),
+ )
controller.setAllowed(false)
@@ -135,12 +112,7 @@
fun getMode() {
whenever(appOpsManager.checkOpNoThrow(OP, APP.uid, APP.packageName))
.thenReturn(MODE_ALLOWED)
- val controller =
- AppOpsController(
- context = context,
- app = APP,
- op = OP,
- )
+ val controller = AppOpsController(context = context, app = APP, appOps = AppOps(OP))
val mode = controller.getMode()
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
index bb25cf3..07ccdd5 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
@@ -25,6 +25,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
import com.android.settingslib.spaprivileged.framework.common.appOpsManager
+import com.android.settingslib.spaprivileged.model.app.AppOps
import com.android.settingslib.spaprivileged.model.app.IAppOpsController
import com.android.settingslib.spaprivileged.model.app.IPackageManagers
import com.android.settingslib.spaprivileged.test.R
@@ -39,7 +40,6 @@
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
-import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
@@ -287,16 +287,6 @@
assertThat(appOpsController.setAllowedCalledWith).isTrue()
}
- @Test
- fun setAllowed_setModeByUid() {
- listModel.setModeByUid = true
- val record = listModel.transformItem(APP)
-
- listModel.setAllowed(record = record, newAllowed = true)
-
- verify(appOpsManager).setUidMode(listModel.appOp, APP.uid, AppOpsManager.MODE_ALLOWED)
- }
-
private fun getIsAllowed(record: AppOpPermissionRecord): Boolean? {
lateinit var isAllowedState: () -> Boolean?
composeTestRule.setContent { isAllowedState = listModel.isAllowed(record) }
@@ -309,11 +299,9 @@
override val switchTitleResId = R.string.test_app_op_permission_switch_title
override val footerResId = R.string.test_app_op_permission_footer
- override val appOp = AppOpsManager.OP_MANAGE_MEDIA
+ override val appOps = AppOps(AppOpsManager.OP_MANAGE_MEDIA)
override val permission = PERMISSION
override var broaderPermission: String? = null
-
- override var setModeByUid = false
}
private companion object {
@@ -329,7 +317,7 @@
private class FakeAppOpsController(private val fakeMode: Int) : IAppOpsController {
var setAllowedCalledWith: Boolean? = null
- override val mode = flowOf(fakeMode)
+ override val modeFlow = flowOf(fakeMode)
override fun setAllowed(allowed: Boolean) {
setAllowedCalledWith = allowed
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 8fc4ecc..0ef12e2 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -504,6 +504,15 @@
}
}
+flag {
+ name: "screenshot_scroll_crop_view_crash_fix"
+ namespace: "systemui"
+ description: "Mitigate crash on invalid computed range in CropView"
+ bug: "232633995"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
flag {
name: "screenshot_private_profile_behavior_fix"
diff --git a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
index 5755dcd..01b9f7e 100644
--- a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
@@ -26,8 +26,8 @@
android:paddingVertical="16dp"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@+id/rightGuideline"
- app:layout_constraintStart_toStartOf="@+id/leftGuideline"
+ app:layout_constraintRight_toLeftOf="@+id/rightGuideline"
+ app:layout_constraintLeft_toLeftOf="@+id/leftGuideline"
app:layout_constraintTop_toTopOf="@+id/topGuideline" />
<com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
@@ -35,8 +35,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="@tools:sample/avatars" />
@@ -63,8 +63,8 @@
android:paddingTop="24dp"
android:fadeScrollbars="false"
app:layout_constraintBottom_toTopOf="@+id/button_bar"
- app:layout_constraintEnd_toStartOf="@+id/midGuideline"
- app:layout_constraintStart_toStartOf="@id/leftGuideline"
+ app:layout_constraintRight_toLeftOf="@+id/midGuideline"
+ app:layout_constraintLeft_toLeftOf="@id/leftGuideline"
app:layout_constraintTop_toTopOf="@+id/topGuideline">
<androidx.constraintlayout.widget.ConstraintLayout
@@ -89,7 +89,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textAlignment="viewStart"
- android:paddingLeft="16dp"
+ android:paddingStart="16dp"
app:layout_constraintBottom_toBottomOf="@+id/logo"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/logo"
@@ -209,6 +209,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
+ app:guidelineUseRtl="false"
app:layout_constraintGuide_begin="@dimen/biometric_dialog_border_padding" />
<androidx.constraintlayout.widget.Guideline
@@ -216,6 +217,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
+ app:guidelineUseRtl="false"
app:layout_constraintGuide_end="@dimen/biometric_dialog_border_padding" />
<androidx.constraintlayout.widget.Guideline
@@ -223,6 +225,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
+ app:guidelineUseRtl="false"
app:layout_constraintGuide_begin="406dp" />
<androidx.constraintlayout.widget.Guideline
diff --git a/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml b/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml
index 4d2310a..0bbe73c 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml
@@ -27,7 +27,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:layout_marginLeft="24dp"
+ android:layout_marginStart="24dp"
android:ellipsize="end"
android:maxLines="2"
android:visibility="invisible"
@@ -41,7 +41,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:layout_marginLeft="24dp"
+ android:layout_marginStart="24dp"
android:text="@string/cancel"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
@@ -54,7 +54,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:layout_marginLeft="24dp"
+ android:layout_marginStart="24dp"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
@@ -66,7 +66,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:layout_marginRight="24dp"
+ android:layout_marginEnd="24dp"
android:ellipsize="end"
android:maxLines="2"
android:text="@string/biometric_dialog_confirm"
@@ -81,7 +81,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:layout_marginRight="24dp"
+ android:layout_marginEnd="24dp"
android:ellipsize="end"
android:maxLines="2"
android:text="@string/biometric_dialog_try_again"
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
index f0969ed..13ea3f5 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
@@ -199,29 +199,32 @@
iconParams.leftMargin = position.left
mediumConstraintSet.clear(
R.id.biometric_icon,
- ConstraintSet.END
+ ConstraintSet.RIGHT
)
mediumConstraintSet.connect(
R.id.biometric_icon,
- ConstraintSet.START,
+ ConstraintSet.LEFT,
ConstraintSet.PARENT_ID,
- ConstraintSet.START
+ ConstraintSet.LEFT
)
mediumConstraintSet.setMargin(
R.id.biometric_icon,
- ConstraintSet.START,
+ ConstraintSet.LEFT,
position.left
)
- smallConstraintSet.clear(R.id.biometric_icon, ConstraintSet.END)
+ smallConstraintSet.clear(
+ R.id.biometric_icon,
+ ConstraintSet.RIGHT
+ )
smallConstraintSet.connect(
R.id.biometric_icon,
- ConstraintSet.START,
+ ConstraintSet.LEFT,
ConstraintSet.PARENT_ID,
- ConstraintSet.START
+ ConstraintSet.LEFT
)
smallConstraintSet.setMargin(
R.id.biometric_icon,
- ConstraintSet.START,
+ ConstraintSet.LEFT,
position.left
)
}
@@ -252,32 +255,32 @@
iconParams.rightMargin = position.right
mediumConstraintSet.clear(
R.id.biometric_icon,
- ConstraintSet.START
+ ConstraintSet.LEFT
)
mediumConstraintSet.connect(
R.id.biometric_icon,
- ConstraintSet.END,
+ ConstraintSet.RIGHT,
ConstraintSet.PARENT_ID,
- ConstraintSet.END
+ ConstraintSet.RIGHT
)
mediumConstraintSet.setMargin(
R.id.biometric_icon,
- ConstraintSet.END,
+ ConstraintSet.RIGHT,
position.right
)
smallConstraintSet.clear(
R.id.biometric_icon,
- ConstraintSet.START
+ ConstraintSet.LEFT
)
smallConstraintSet.connect(
R.id.biometric_icon,
- ConstraintSet.END,
+ ConstraintSet.RIGHT,
ConstraintSet.PARENT_ID,
- ConstraintSet.END
+ ConstraintSet.RIGHT
)
smallConstraintSet.setMargin(
R.id.biometric_icon,
- ConstraintSet.END,
+ ConstraintSet.RIGHT,
position.right
)
}
@@ -383,15 +386,15 @@
// Move all content to other panel
flipConstraintSet.connect(
R.id.scrollView,
- ConstraintSet.START,
+ ConstraintSet.LEFT,
R.id.midGuideline,
- ConstraintSet.START
+ ConstraintSet.LEFT
)
flipConstraintSet.connect(
R.id.scrollView,
- ConstraintSet.END,
+ ConstraintSet.RIGHT,
R.id.rightGuideline,
- ConstraintSet.END
+ ConstraintSet.RIGHT
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileStateToProto.kt b/packages/SystemUI/src/com/android/systemui/qs/TileStateToProto.kt
index 2c8a5a4..1336d64 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileStateToProto.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileStateToProto.kt
@@ -18,6 +18,7 @@
import android.service.quicksettings.Tile
import android.text.TextUtils
+import android.widget.Switch
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.qs.external.CustomTile
import com.android.systemui.qs.nano.QsTileState
@@ -44,8 +45,8 @@
}
label?.let { state.label = it.toString() }
secondaryLabel?.let { state.secondaryLabel = it.toString() }
- if (this is QSTile.BooleanState) {
- state.booleanState = value
+ if (expandedAccessibilityClassName == Switch::class.java.name) {
+ state.booleanState = state.state == QsTileState.ACTIVE
}
return state
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index d26ae0a..5d35a69 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -42,6 +42,7 @@
import android.util.Log;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
+import android.widget.Button;
import android.widget.Switch;
import androidx.annotation.Nullable;
@@ -502,6 +503,8 @@
if (state instanceof BooleanState) {
state.expandedAccessibilityClassName = Switch.class.getName();
((BooleanState) state).value = (state.state == Tile.STATE_ACTIVE);
+ } else {
+ state.expandedAccessibilityClassName = Button.class.getName();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/scroll/CropView.java b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/CropView.java
index 5e561cf..ee1944e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/scroll/CropView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/CropView.java
@@ -45,6 +45,7 @@
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import com.android.internal.graphics.ColorUtils;
+import com.android.systemui.Flags;
import com.android.systemui.res.R;
import java.util.List;
@@ -378,8 +379,14 @@
upper = 1;
break;
}
- Log.i(TAG, "getAllowedValues: " + boundary + ", "
- + "result=[lower=" + lower + ", upper=" + upper + "]");
+ if (lower >= upper) {
+ Log.wtf(TAG, "getAllowedValues computed an invalid range "
+ + "[" + lower + ", " + upper + "]");
+ if (Flags.screenshotScrollCropViewCrashFix()) {
+ lower = Math.min(lower, upper);
+ upper = lower;
+ }
+ }
return new Range<>(lower, upper);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
index f44e7f3..8b48bd3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
@@ -22,6 +22,7 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
import com.android.systemui.statusbar.policy.BaseHeadsUpManager.HeadsUpEntry
+import com.android.systemui.util.Compile
import java.io.PrintWriter
import javax.inject.Inject
@@ -37,7 +38,7 @@
) : Dumpable {
private val tag = "AvalancheController"
- private val debug = false
+ private val debug = Compile.IS_DEBUG && Log.isLoggable(tag, Log.DEBUG)
// HUN showing right now, in the floating state where full shade is hidden, on launcher or AOD
@VisibleForTesting var headsUpEntryShowing: HeadsUpEntry? = null
@@ -108,7 +109,10 @@
if (isOnlyNextEntry) {
// HeadsUpEntry.updateEntry recursively calls AvalancheController#update
// and goes to the isShowing case above
- headsUpEntryShowing!!.updateEntry(false, "avalanche duration update")
+ headsUpEntryShowing!!.updateEntry(
+ /* updatePostTime= */ false,
+ /* updateEarliestRemovalTime= */ false,
+ /* reason= */ "avalanche duration update")
}
}
logState("after $fn")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
index b8318a7..a7fe49b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
@@ -39,6 +39,7 @@
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
+import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor;
import com.android.systemui.util.ListenerSet;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -114,7 +115,8 @@
mUiEventLogger = uiEventLogger;
mAvalancheController = avalancheController;
Resources resources = context.getResources();
- mMinimumDisplayTime = resources.getInteger(R.integer.heads_up_notification_minimum_time);
+ mMinimumDisplayTime = NotificationThrottleHun.isEnabled()
+ ? 500 : resources.getInteger(R.integer.heads_up_notification_minimum_time);
mStickyForSomeTimeAutoDismissTime = resources.getInteger(
R.integer.sticky_heads_up_notification_time);
mAutoDismissTime = resources.getInteger(R.integer.heads_up_notification_decay);
@@ -765,11 +767,23 @@
* @param updatePostTime whether or not to refresh the post time
*/
public void updateEntry(boolean updatePostTime, @Nullable String reason) {
+ updateEntry(updatePostTime, /* updateEarliestRemovalTime= */ true, reason);
+ }
+
+ /**
+ * Updates an entry's removal time.
+ * @param updatePostTime whether or not to refresh the post time
+ * @param updateEarliestRemovalTime whether this update should further delay removal
+ */
+ public void updateEntry(boolean updatePostTime, boolean updateEarliestRemovalTime,
+ @Nullable String reason) {
Runnable runnable = () -> {
mLogger.logUpdateEntry(mEntry, updatePostTime, reason);
final long now = mSystemClock.elapsedRealtime();
- mEarliestRemovalTime = now + mMinimumDisplayTime;
+ if (updateEarliestRemovalTime) {
+ mEarliestRemovalTime = now + mMinimumDisplayTime;
+ }
if (updatePostTime) {
mPostTime = Math.max(mPostTime, now);
@@ -785,7 +799,9 @@
FinishTimeUpdater finishTimeCalculator = () -> {
final long finishTime = calculateFinishTime();
final long now = mSystemClock.elapsedRealtime();
- final long timeLeft = Math.max(finishTime - now, mMinimumDisplayTime);
+ final long timeLeft = NotificationThrottleHun.isEnabled()
+ ? Math.max(finishTime, mEarliestRemovalTime) - now
+ : Math.max(finishTime - now, mMinimumDisplayTime);
return timeLeft;
};
scheduleAutoRemovalCallback(finishTimeCalculator, "updateEntry (not sticky)");
@@ -818,13 +834,6 @@
}
public int compareNonTimeFields(HeadsUpEntry headsUpEntry) {
- boolean isPinned = mEntry.isRowPinned();
- boolean otherPinned = headsUpEntry.mEntry.isRowPinned();
- if (isPinned && !otherPinned) {
- return -1;
- } else if (!isPinned && otherPinned) {
- return 1;
- }
boolean selfFullscreen = hasFullScreenIntent(mEntry);
boolean otherFullscreen = hasFullScreenIntent(headsUpEntry.mEntry);
if (selfFullscreen && !otherFullscreen) {
@@ -851,6 +860,13 @@
}
public int compareTo(@NonNull HeadsUpEntry headsUpEntry) {
+ boolean isPinned = mEntry.isRowPinned();
+ boolean otherPinned = headsUpEntry.mEntry.isRowPinned();
+ if (isPinned && !otherPinned) {
+ return -1;
+ } else if (!isPinned && otherPinned) {
+ return 1;
+ }
int nonTimeCompareResult = compareNonTimeFields(headsUpEntry);
if (nonTimeCompareResult != 0) {
return nonTimeCompareResult;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileStateToProtoTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/TileStateToProtoTest.kt
index 629c663..bc947fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/TileStateToProtoTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TileStateToProtoTest.kt
@@ -3,6 +3,7 @@
import android.content.ComponentName
import android.service.quicksettings.Tile
import android.testing.AndroidTestingRunner
+import android.widget.Switch
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.qs.QSTile
@@ -66,15 +67,19 @@
assertThat(proto?.hasBooleanState()).isFalse()
}
+ /**
+ * The [QSTile.AdapterState.expandedAccessibilityClassName] setting to [Switch] results in the
+ * proto having a booleanState. The value of that boolean is true iff the tile is active.
+ */
@Test
- fun booleanState_ACTIVE() {
+ fun adapterState_ACTIVE() {
val state =
- QSTile.BooleanState().apply {
+ QSTile.AdapterState().apply {
spec = TEST_SPEC
label = TEST_LABEL
secondaryLabel = TEST_SUBTITLE
state = Tile.STATE_ACTIVE
- value = true
+ expandedAccessibilityClassName = Switch::class.java.name
}
val proto = state.toProto()
@@ -89,6 +94,33 @@
assertThat(proto?.booleanState).isTrue()
}
+ /**
+ * Similar to [adapterState_ACTIVE], the use of
+ * [QSTile.AdapterState.expandedAccessibilityClassName] signals that the tile is toggleable.
+ */
+ @Test
+ fun adapterState_INACTIVE() {
+ val state =
+ QSTile.AdapterState().apply {
+ spec = TEST_SPEC
+ label = TEST_LABEL
+ secondaryLabel = TEST_SUBTITLE
+ state = Tile.STATE_INACTIVE
+ expandedAccessibilityClassName = Switch::class.java.name
+ }
+ val proto = state.toProto()
+
+ assertThat(proto).isNotNull()
+ assertThat(proto?.hasSpec()).isTrue()
+ assertThat(proto?.spec).isEqualTo(TEST_SPEC)
+ assertThat(proto?.hasComponentName()).isFalse()
+ assertThat(proto?.label).isEqualTo(TEST_LABEL)
+ assertThat(proto?.secondaryLabel).isEqualTo(TEST_SUBTITLE)
+ assertThat(proto?.state).isEqualTo(Tile.STATE_INACTIVE)
+ assertThat(proto?.hasBooleanState()).isTrue()
+ assertThat(proto?.booleanState).isFalse()
+ }
+
@Test
fun noSpec_returnsNull() {
val state =
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 4f84149..58732fd 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -159,6 +159,8 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* All information we are collecting about things that can happen that impact
@@ -409,26 +411,14 @@
com.android.internal.R.bool.config_batteryStatsResetOnUnplugHighBatteryLevel);
final boolean resetOnUnplugAfterSignificantCharge = context.getResources().getBoolean(
com.android.internal.R.bool.config_batteryStatsResetOnUnplugAfterSignificantCharge);
- final long powerStatsThrottlePeriodCpu = context.getResources().getInteger(
- com.android.internal.R.integer.config_defaultPowerStatsThrottlePeriodCpu);
- final long powerStatsThrottlePeriodMobileRadio = context.getResources().getInteger(
- com.android.internal.R.integer.config_defaultPowerStatsThrottlePeriodMobileRadio);
- final long powerStatsThrottlePeriodWifi = context.getResources().getInteger(
- com.android.internal.R.integer.config_defaultPowerStatsThrottlePeriodWifi);
- mBatteryStatsConfig =
+ BatteryStatsImpl.BatteryStatsConfig.Builder batteryStatsConfigBuilder =
new BatteryStatsImpl.BatteryStatsConfig.Builder()
.setResetOnUnplugHighBatteryLevel(resetOnUnplugHighBatteryLevel)
- .setResetOnUnplugAfterSignificantCharge(resetOnUnplugAfterSignificantCharge)
- .setPowerStatsThrottlePeriodMillis(
- BatteryConsumer.POWER_COMPONENT_CPU,
- powerStatsThrottlePeriodCpu)
- .setPowerStatsThrottlePeriodMillis(
- BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
- powerStatsThrottlePeriodMobileRadio)
- .setPowerStatsThrottlePeriodMillis(
- BatteryConsumer.POWER_COMPONENT_WIFI,
- powerStatsThrottlePeriodWifi)
- .build();
+ .setResetOnUnplugAfterSignificantCharge(
+ resetOnUnplugAfterSignificantCharge);
+ setPowerStatsThrottlePeriods(batteryStatsConfigBuilder, context.getResources().getString(
+ com.android.internal.R.string.config_powerStatsThrottlePeriods));
+ mBatteryStatsConfig = batteryStatsConfigBuilder.build();
mPowerStatsUidResolver = new PowerStatsUidResolver();
mStats = new BatteryStatsImpl(mBatteryStatsConfig, Clock.SYSTEM_CLOCK, mMonotonicClock,
systemDir, mHandler, this, this, mUserManagerUserInfoProvider, mPowerProfile,
@@ -515,6 +505,26 @@
return config;
}
+ private void setPowerStatsThrottlePeriods(BatteryStatsImpl.BatteryStatsConfig.Builder builder,
+ String configString) {
+ Matcher matcher = Pattern.compile("([^:]+):(\\d+)\\s*").matcher(configString);
+ while (matcher.find()) {
+ String powerComponentName = matcher.group(1);
+ long throttlePeriod;
+ try {
+ throttlePeriod = Long.parseLong(matcher.group(2));
+ } catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException(
+ "Invalid config_powerStatsThrottlePeriods format: " + configString);
+ }
+ if (powerComponentName.equals("*")) {
+ builder.setDefaultPowerStatsThrottlePeriodMillis(throttlePeriod);
+ } else {
+ builder.setPowerStatsThrottlePeriodMillis(powerComponentName, throttlePeriod);
+ }
+ }
+ }
+
/**
* Creates an instance of BatteryStatsService and restores data from stored state.
*/
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 46061a5..275c930 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -206,6 +206,10 @@
launchDeviceDiscovery();
startQueuedActions();
if (!mDelayedMessageBuffer.isBuffered(Constants.MESSAGE_ACTIVE_SOURCE)) {
+ if (hasAction(RequestActiveSourceAction.class)) {
+ Slog.i(TAG, "RequestActiveSourceAction is in progress. Restarting.");
+ removeAction(RequestActiveSourceAction.class);
+ }
addAndStartAction(new RequestActiveSourceAction(this, new IHdmiControlCallback.Stub() {
@Override
public void onComplete(int result) {
@@ -1308,6 +1312,8 @@
mService.sendCecCommand(
HdmiCecMessageBuilder.buildActiveSource(
getDeviceInfo().getLogicalAddress(), activePath));
+ updateActiveSource(getDeviceInfo().getLogicalAddress(), activePath,
+ "HdmiCecLocalDeviceTv#launchRoutingControl()");
}
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 936e8b6..05c4aa6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1646,6 +1646,13 @@
case Constants.MESSAGE_ROUTING_CHANGE:
case Constants.MESSAGE_SET_STREAM_PATH:
case Constants.MESSAGE_TEXT_VIEW_ON:
+ // RequestActiveSourceAction is started after the TV finished logical address
+ // allocation. This action is used by the TV to get the active source from the CEC
+ // network. If the TV sent a source changing CEC message, this action does not have
+ // to continue anymore.
+ if (isTvDevice()) {
+ tv().removeAction(RequestActiveSourceAction.class);
+ }
sendCecCommandWithRetries(command, callback);
break;
default:
diff --git a/services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java b/services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java
index d250416..539a00d 100644
--- a/services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestActiveSourceAction.java
@@ -21,13 +21,20 @@
import android.util.Slog;
/**
- * Feature action that sends <Request Active Source> message and waits for <Active Source>.
+ * Feature action that sends <Request Active Source> message and waits for <Active Source> on TV
+ * panels.
+ * This action has a delay before sending <Request Active Source>. This is because it should wait
+ * for a possible request from LauncherX and can be cancelled if an <Active Source> message was
+ * received or the TV switched to another input.
*/
public class RequestActiveSourceAction extends HdmiCecFeatureAction {
private static final String TAG = "RequestActiveSourceAction";
+ // State to wait for the LauncherX to call the CEC API.
+ private static final int STATE_WAIT_FOR_LAUNCHERX_API_CALL = 1;
+
// State to wait for the <Active Source> message.
- private static final int STATE_WAIT_FOR_ACTIVE_SOURCE = 1;
+ private static final int STATE_WAIT_FOR_ACTIVE_SOURCE = 2;
// Number of retries <Request Active Source> is sent if no device answers this message.
private static final int MAX_SEND_RETRY_COUNT = 1;
@@ -43,10 +50,12 @@
boolean start() {
Slog.v(TAG, "RequestActiveSourceAction started.");
- sendCommand(HdmiCecMessageBuilder.buildRequestActiveSource(getSourceAddress()));
+ mState = STATE_WAIT_FOR_LAUNCHERX_API_CALL;
- mState = STATE_WAIT_FOR_ACTIVE_SOURCE;
- addTimer(mState, HdmiConfig.TIMEOUT_MS);
+ // We wait for default timeout to allow the message triggered by the LauncherX API call to
+ // be sent by the TV and another default timeout in case the message has to be answered
+ // (e.g. TV sent a <Set Stream Path> or <Routing Change>).
+ addTimer(mState, HdmiConfig.TIMEOUT_MS * 2);
return true;
}
@@ -65,13 +74,23 @@
if (mState != state) {
return;
}
- if (mState == STATE_WAIT_FOR_ACTIVE_SOURCE) {
- if (mSendRetryCount++ < MAX_SEND_RETRY_COUNT) {
+
+ switch (mState) {
+ case STATE_WAIT_FOR_LAUNCHERX_API_CALL:
+ mState = STATE_WAIT_FOR_ACTIVE_SOURCE;
sendCommand(HdmiCecMessageBuilder.buildRequestActiveSource(getSourceAddress()));
addTimer(mState, HdmiConfig.TIMEOUT_MS);
- } else {
- finishWithCallback(HdmiControlManager.RESULT_TIMEOUT);
- }
+ return;
+ case STATE_WAIT_FOR_ACTIVE_SOURCE:
+ if (mSendRetryCount++ < MAX_SEND_RETRY_COUNT) {
+ sendCommand(HdmiCecMessageBuilder.buildRequestActiveSource(getSourceAddress()));
+ addTimer(mState, HdmiConfig.TIMEOUT_MS);
+ } else {
+ finishWithCallback(HdmiControlManager.RESULT_TIMEOUT);
+ }
+ return;
+ default:
+ return;
}
}
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 8685d2c..8e85b81 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -2671,24 +2671,6 @@
return null;
}
- private static class PointerDisplayIdChangedArgs {
- final int mPointerDisplayId;
- final float mXPosition;
- final float mYPosition;
- PointerDisplayIdChangedArgs(int pointerDisplayId, float xPosition, float yPosition) {
- mPointerDisplayId = pointerDisplayId;
- mXPosition = xPosition;
- mYPosition = yPosition;
- }
- }
-
- // Native callback.
- @SuppressWarnings("unused")
- @VisibleForTesting
- void onPointerDisplayIdChanged(int pointerDisplayId, float xPosition, float yPosition) {
- // TODO(b/311416205): Remove.
- }
-
@Override
@EnforcePermission(Manifest.permission.MONITOR_STICKY_MODIFIER_STATE)
public void registerStickyModifierStateListener(
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 121cf3f..fda8535 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4003,7 +4003,7 @@
final PackageMetrics.ComponentStateMetrics componentStateMetrics =
new PackageMetrics.ComponentStateMetrics(setting,
UserHandle.getUid(userId, packageSetting.getAppId()),
- packageSetting.getEnabled(userId));
+ packageSetting.getEnabled(userId), callingUid);
if (!setEnabledSettingInternalLocked(computer, packageSetting, setting, userId,
callingPackage)) {
continue;
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 7a36f6d..0a8b2b2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -328,6 +328,8 @@
return runGetPrivappDenyPermissions();
case "get-oem-permissions":
return runGetOemPermissions();
+ case "get-signature-permission-allowlist":
+ return runGetSignaturePermissionAllowlist();
case "trim-caches":
return runTrimCaches();
case "create-user":
@@ -2920,6 +2922,54 @@
return 0;
}
+ private int runGetSignaturePermissionAllowlist() {
+ final var partition = getNextArg();
+ if (partition == null) {
+ getErrPrintWriter().println("Error: no partition specified.");
+ return 1;
+ }
+ final var permissionAllowlist =
+ SystemConfig.getInstance().getPermissionAllowlist();
+ final ArrayMap<String, ArrayMap<String, Boolean>> allowlist;
+ switch (partition) {
+ case "system":
+ allowlist = permissionAllowlist.getSignatureAppAllowlist();
+ break;
+ case "vendor":
+ allowlist = permissionAllowlist.getVendorSignatureAppAllowlist();
+ break;
+ case "product":
+ allowlist = permissionAllowlist.getProductSignatureAppAllowlist();
+ break;
+ case "system-ext":
+ allowlist = permissionAllowlist.getSystemExtSignatureAppAllowlist();
+ break;
+ default:
+ getErrPrintWriter().println("Error: unknown partition: " + partition);
+ return 1;
+ }
+ final var ipw = new IndentingPrintWriter(getOutPrintWriter(), " ");
+ final var allowlistSize = allowlist.size();
+ for (var allowlistIndex = 0; allowlistIndex < allowlistSize; allowlistIndex++) {
+ final var packageName = allowlist.keyAt(allowlistIndex);
+ final var permissions = allowlist.valueAt(allowlistIndex);
+ ipw.print("Package: ");
+ ipw.println(packageName);
+ ipw.increaseIndent();
+ final var permissionsSize = permissions.size();
+ for (var permissionsIndex = 0; permissionsIndex < permissionsSize; permissionsIndex++) {
+ final var permissionName = permissions.keyAt(permissionsIndex);
+ final var granted = permissions.valueAt(permissionsIndex);
+ if (granted) {
+ ipw.print("Permission: ");
+ ipw.println(permissionName);
+ }
+ }
+ ipw.decreaseIndent();
+ }
+ return 0;
+ }
+
private int runTrimCaches() throws RemoteException {
String size = getNextArg();
if (size == null) {
@@ -4852,6 +4902,10 @@
pw.println(" get-oem-permissions TARGET-PACKAGE");
pw.println(" Prints all OEM permissions for a package.");
pw.println("");
+ pw.println(" get-signature-permission-allowlist PARTITION");
+ pw.println(" Prints the signature permission allowlist for a partition.");
+ pw.println(" PARTITION is one of system, vendor, product and system-ext");
+ pw.println("");
pw.println(" trim-caches DESIRED_FREE_SPACE [internal|UUID]");
pw.println(" Trim cache files to reach the given free space.");
pw.println("");
diff --git a/services/core/java/com/android/server/pm/PackageMetrics.java b/services/core/java/com/android/server/pm/PackageMetrics.java
index 20598f9..2081f73 100644
--- a/services/core/java/com/android/server/pm/PackageMetrics.java
+++ b/services/core/java/com/android/server/pm/PackageMetrics.java
@@ -358,6 +358,7 @@
public static class ComponentStateMetrics {
public int mUid;
+ public int mCallingUid;
public int mComponentOldState;
public int mComponentNewState;
public boolean mIsForWholeApp;
@@ -365,13 +366,14 @@
@Nullable private String mClassName;
ComponentStateMetrics(@NonNull PackageManager.ComponentEnabledSetting setting, int uid,
- int componentOldState) {
+ int componentOldState, int callingUid) {
mUid = uid;
mComponentOldState = componentOldState;
mComponentNewState = setting.getEnabledState();
mIsForWholeApp = !setting.isComponent();
mPackageName = setting.getPackageName();
mClassName = setting.getClassName();
+ mCallingUid = callingUid;
}
public boolean isSameComponent(ActivityInfo activityInfo) {
@@ -412,14 +414,15 @@
componentStateMetrics.mComponentOldState,
componentStateMetrics.mComponentNewState,
isLauncher,
- componentStateMetrics.mIsForWholeApp);
+ componentStateMetrics.mIsForWholeApp,
+ componentStateMetrics.mCallingUid);
}
}
private static void reportComponentStateChanged(int uid, int componentOldState,
- int componentNewState, boolean isLauncher, boolean isForWholeApp) {
+ int componentNewState, boolean isLauncher, boolean isForWholeApp, int callingUid) {
FrameworkStatsLog.write(FrameworkStatsLog.COMPONENT_STATE_CHANGED_REPORTED,
- uid, componentOldState, componentNewState, isLauncher, isForWholeApp);
+ uid, componentOldState, componentNewState, isLauncher, isForWholeApp, callingUid);
}
private static List<ResolveInfo> getHomeActivitiesResolveInfoAsUser(@NonNull Computer computer,
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 41d6288..8d6d774 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2142,7 +2142,8 @@
ComponentName unflattenOriginalComponentName = ComponentName.unflattenFromString(
originalComponentName);
if (unflattenOriginalComponentName == null) {
- Slog.d(TAG, "Incorrect component name from the attributes");
+ Slog.wtf(TAG, "Incorrect component name: " + originalComponentName
+ + " from the attributes");
continue;
}
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 49c4000..9a41551 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -463,11 +463,17 @@
public static class BatteryStatsConfig {
static final int RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG = 1 << 0;
static final int RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG = 1 << 1;
- static final long DEFAULT_POWER_STATS_COLLECTION_THROTTLE_PERIOD =
- TimeUnit.HOURS.toMillis(1);
private final int mFlags;
- private SparseLongArray mPowerStatsThrottlePeriods;
+ private final Long mDefaultPowerStatsThrottlePeriod;
+ private final Map<String, Long> mPowerStatsThrottlePeriods;
+
+ @VisibleForTesting
+ public BatteryStatsConfig() {
+ mFlags = 0;
+ mDefaultPowerStatsThrottlePeriod = 0L;
+ mPowerStatsThrottlePeriods = Map.of();
+ }
private BatteryStatsConfig(Builder builder) {
int flags = 0;
@@ -478,6 +484,7 @@
flags |= RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG;
}
mFlags = flags;
+ mDefaultPowerStatsThrottlePeriod = builder.mDefaultPowerStatsThrottlePeriod;
mPowerStatsThrottlePeriods = builder.mPowerStatsThrottlePeriods;
}
@@ -485,7 +492,7 @@
* Returns whether a BatteryStats reset should occur on unplug when the battery level is
* high.
*/
- boolean shouldResetOnUnplugHighBatteryLevel() {
+ public boolean shouldResetOnUnplugHighBatteryLevel() {
return (mFlags & RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG)
== RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG;
}
@@ -494,14 +501,18 @@
* Returns whether a BatteryStats reset should occur on unplug if the battery charge a
* significant amount since it has been plugged in.
*/
- boolean shouldResetOnUnplugAfterSignificantCharge() {
+ public boolean shouldResetOnUnplugAfterSignificantCharge() {
return (mFlags & RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG)
== RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG;
}
- long getPowerStatsThrottlePeriod(@BatteryConsumer.PowerComponent int powerComponent) {
- return mPowerStatsThrottlePeriods.get(powerComponent,
- DEFAULT_POWER_STATS_COLLECTION_THROTTLE_PERIOD);
+ /**
+ * Returns the minimum amount of time (in millis) to wait between passes
+ * of power stats collection for the specified power component.
+ */
+ public long getPowerStatsThrottlePeriod(String powerComponentName) {
+ return mPowerStatsThrottlePeriods.getOrDefault(powerComponentName,
+ mDefaultPowerStatsThrottlePeriod);
}
/**
@@ -510,18 +521,19 @@
public static class Builder {
private boolean mResetOnUnplugHighBatteryLevel;
private boolean mResetOnUnplugAfterSignificantCharge;
- private SparseLongArray mPowerStatsThrottlePeriods;
+ public static final long DEFAULT_POWER_STATS_THROTTLE_PERIOD =
+ TimeUnit.HOURS.toMillis(1);
+ public static final long DEFAULT_POWER_STATS_THROTTLE_PERIOD_CPU =
+ TimeUnit.MINUTES.toMillis(1);
+ private long mDefaultPowerStatsThrottlePeriod = DEFAULT_POWER_STATS_THROTTLE_PERIOD;
+ private final Map<String, Long> mPowerStatsThrottlePeriods = new HashMap<>();
public Builder() {
mResetOnUnplugHighBatteryLevel = true;
mResetOnUnplugAfterSignificantCharge = true;
- mPowerStatsThrottlePeriods = new SparseLongArray();
- setPowerStatsThrottlePeriodMillis(BatteryConsumer.POWER_COMPONENT_CPU,
- TimeUnit.MINUTES.toMillis(1));
- setPowerStatsThrottlePeriodMillis(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
- TimeUnit.HOURS.toMillis(1));
- setPowerStatsThrottlePeriodMillis(BatteryConsumer.POWER_COMPONENT_WIFI,
- TimeUnit.HOURS.toMillis(1));
+ setPowerStatsThrottlePeriodMillis(BatteryConsumer.powerComponentIdToString(
+ BatteryConsumer.POWER_COMPONENT_CPU),
+ DEFAULT_POWER_STATS_THROTTLE_PERIOD_CPU);
}
/**
@@ -553,9 +565,18 @@
* Sets the minimum amount of time (in millis) to wait between passes
* of power stats collection for the specified power component.
*/
- public Builder setPowerStatsThrottlePeriodMillis(
- @BatteryConsumer.PowerComponent int powerComponent, long periodMs) {
- mPowerStatsThrottlePeriods.put(powerComponent, periodMs);
+ public Builder setPowerStatsThrottlePeriodMillis(String powerComponentName,
+ long periodMs) {
+ mPowerStatsThrottlePeriods.put(powerComponentName, periodMs);
+ return this;
+ }
+
+ /**
+ * Sets the minimum amount of time (in millis) to wait between passes
+ * of power stats collection for any components not configured explicitly.
+ */
+ public Builder setDefaultPowerStatsThrottlePeriodMillis(long periodMs) {
+ mDefaultPowerStatsThrottlePeriod = periodMs;
return this;
}
}
@@ -1586,8 +1607,7 @@
protected final Constants mConstants;
@VisibleForTesting
- @GuardedBy("this")
- protected BatteryStatsConfig mBatteryStatsConfig;
+ protected final BatteryStatsConfig mBatteryStatsConfig;
@GuardedBy("this")
private AlarmManager mAlarmManager = null;
@@ -1933,6 +1953,11 @@
}
@Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return mBatteryStatsConfig.getPowerStatsThrottlePeriod(powerComponentName);
+ }
+
+ @Override
public PowerStatsUidResolver getUidResolver() {
return mPowerStatsUidResolver;
}
@@ -11167,19 +11192,14 @@
mConstants.MAX_HISTORY_FILES, mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator,
mClock, mMonotonicClock, traceDelegate, eventLogger);
- mCpuPowerStatsCollector = new CpuPowerStatsCollector(mPowerStatsCollectorInjector,
- mBatteryStatsConfig.getPowerStatsThrottlePeriod(
- BatteryConsumer.POWER_COMPONENT_CPU));
+ mCpuPowerStatsCollector = new CpuPowerStatsCollector(mPowerStatsCollectorInjector);
mCpuPowerStatsCollector.addConsumer(this::recordPowerStats);
mMobileRadioPowerStatsCollector = new MobileRadioPowerStatsCollector(
- mPowerStatsCollectorInjector, mBatteryStatsConfig.getPowerStatsThrottlePeriod(
- BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO));
+ mPowerStatsCollectorInjector);
mMobileRadioPowerStatsCollector.addConsumer(this::recordPowerStats);
- mWifiPowerStatsCollector = new WifiPowerStatsCollector(
- mPowerStatsCollectorInjector, mBatteryStatsConfig.getPowerStatsThrottlePeriod(
- BatteryConsumer.POWER_COMPONENT_WIFI));
+ mWifiPowerStatsCollector = new WifiPowerStatsCollector(mPowerStatsCollectorInjector);
mWifiPowerStatsCollector.addConsumer(this::recordPowerStats);
mStartCount++;
diff --git a/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java
index f53a1b0..b5ef67b 100644
--- a/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java
@@ -59,6 +59,7 @@
KernelCpuStatsReader getKernelCpuStatsReader();
ConsumedEnergyRetriever getConsumedEnergyRetriever();
IntSupplier getVoltageSupplier();
+ long getPowerStatsCollectionThrottlePeriod(String powerComponentName);
default int getDefaultCpuPowerBrackets() {
return DEFAULT_CPU_POWER_BRACKETS;
@@ -94,9 +95,11 @@
private int mLastVoltageMv;
private long[] mLastConsumedEnergyUws;
- public CpuPowerStatsCollector(Injector injector, long throttlePeriodMs) {
- super(injector.getHandler(), throttlePeriodMs, injector.getUidResolver(),
- injector.getClock());
+ CpuPowerStatsCollector(Injector injector) {
+ super(injector.getHandler(), injector.getPowerStatsCollectionThrottlePeriod(
+ BatteryConsumer.powerComponentIdToString(
+ BatteryConsumer.POWER_COMPONENT_CPU)),
+ injector.getUidResolver(), injector.getClock());
mInjector = injector;
}
diff --git a/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsCollector.java
index 7bc6817..a96e01b 100644
--- a/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsCollector.java
@@ -73,6 +73,7 @@
Handler getHandler();
Clock getClock();
PowerStatsUidResolver getUidResolver();
+ long getPowerStatsCollectionThrottlePeriod(String powerComponentName);
PackageManager getPackageManager();
ConsumedEnergyRetriever getConsumedEnergyRetriever();
IntSupplier getVoltageSupplier();
@@ -104,8 +105,11 @@
private long mLastCallDuration;
private long mLastScanDuration;
- public MobileRadioPowerStatsCollector(Injector injector, long throttlePeriodMs) {
- super(injector.getHandler(), throttlePeriodMs, injector.getUidResolver(),
+ MobileRadioPowerStatsCollector(Injector injector) {
+ super(injector.getHandler(), injector.getPowerStatsCollectionThrottlePeriod(
+ BatteryConsumer.powerComponentIdToString(
+ BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)),
+ injector.getUidResolver(),
injector.getClock());
mInjector = injector;
}
diff --git a/services/core/java/com/android/server/power/stats/WifiPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/WifiPowerStatsCollector.java
index 6321053..bd04199 100644
--- a/services/core/java/com/android/server/power/stats/WifiPowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/WifiPowerStatsCollector.java
@@ -56,6 +56,7 @@
Handler getHandler();
Clock getClock();
PowerStatsUidResolver getUidResolver();
+ long getPowerStatsCollectionThrottlePeriod(String powerComponentName);
PackageManager getPackageManager();
ConsumedEnergyRetriever getConsumedEnergyRetriever();
IntSupplier getVoltageSupplier();
@@ -92,9 +93,11 @@
private final SparseArray<WifiScanTimes> mLastScanTimes = new SparseArray<>();
private long mLastWifiActiveDuration;
- public WifiPowerStatsCollector(Injector injector, long throttlePeriodMs) {
- super(injector.getHandler(), throttlePeriodMs, injector.getUidResolver(),
- injector.getClock());
+ WifiPowerStatsCollector(Injector injector) {
+ super(injector.getHandler(), injector.getPowerStatsCollectionThrottlePeriod(
+ BatteryConsumer.powerComponentIdToString(
+ BatteryConsumer.POWER_COMPONENT_WIFI)),
+ injector.getUidResolver(), injector.getClock());
mInjector = injector;
}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 3b9ad19..c1b825b 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -836,9 +836,7 @@
registerEventListeners();
});
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
- if (true) {
- initNetworkStatsManager();
- }
+ initNetworkStatsManager();
BackgroundThread.getHandler().post(() -> {
// Network stats related pullers can only be initialized after service is ready.
initAndRegisterNetworkStatsPullers();
@@ -859,9 +857,6 @@
mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
mStatsSubscriptionsListener = new StatsSubscriptionsListener(mSubscriptionManager);
mStorageManager = (StorageManager) mContext.getSystemService(StorageManager.class);
- if (false) {
- initNetworkStatsManager();
- }
// Initialize DiskIO
mStoragedUidIoStatsReader = new StoragedUidIoStatsReader();
@@ -1043,10 +1038,8 @@
*/
@NonNull
private NetworkStatsManager getNetworkStatsManager() {
- if (true) {
- if (mNetworkStatsManager == null) {
- throw new IllegalStateException("NetworkStatsManager is not ready");
- }
+ if (mNetworkStatsManager == null) {
+ throw new IllegalStateException("NetworkStatsManager is not ready");
}
return mNetworkStatsManager;
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 2b32a30..0066269 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -339,7 +339,6 @@
import android.service.dreams.DreamActivity;
import android.service.voice.IVoiceInteractionSession;
import android.util.ArraySet;
-import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.util.MergedConfiguration;
@@ -2123,14 +2122,14 @@
if (mWmService.mFlags.mInsetsDecoupledConfiguration) {
// When the stable configuration is the default behavior, override for the legacy apps
// without forward override flag.
- mResolveConfigHint.mUseOverrideInsetsForStableBounds =
+ mResolveConfigHint.mUseOverrideInsetsForConfig =
!info.isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED)
&& !info.isChangeEnabled(
OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION);
} else {
// When the stable configuration is not the default behavior, forward overriding the
// listed apps.
- mResolveConfigHint.mUseOverrideInsetsForStableBounds =
+ mResolveConfigHint.mUseOverrideInsetsForConfig =
info.isChangeEnabled(OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION);
}
@@ -5682,6 +5681,8 @@
} else if (mTransitionController.inFinishingTransition(this)) {
mTransitionChangeFlags |= FLAGS_IS_OCCLUDED_NO_ANIMATION;
}
+ } else {
+ mTransitionChangeFlags &= ~FLAG_IS_OCCLUDED;
}
return;
}
@@ -8490,7 +8491,7 @@
mCompatDisplayInsets =
new CompatDisplayInsets(
mDisplayContent, this, letterboxedContainerBounds,
- mResolveConfigHint.mUseOverrideInsetsForStableBounds);
+ mResolveConfigHint.mUseOverrideInsetsForConfig);
}
private void clearSizeCompatModeAttributes() {
@@ -8570,8 +8571,6 @@
final int parentWindowingMode =
newParentConfiguration.windowConfiguration.getWindowingMode();
- applySizeOverrideIfNeeded(newParentConfiguration, parentWindowingMode, resolvedConfig);
-
// Bubble activities should always fill their parent and should not be letterboxed.
final boolean isFixedOrientationLetterboxAllowed = !getLaunchedFromBubble()
&& (parentWindowingMode == WINDOWING_MODE_MULTI_WINDOW
@@ -8671,6 +8670,8 @@
resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds);
}
+ applySizeOverrideIfNeeded(newParentConfiguration, parentWindowingMode, resolvedConfig);
+
logAppCompatState();
}
@@ -8689,14 +8690,13 @@
if (mDisplayContent == null) {
return;
}
- final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
int rotation = newParentConfiguration.windowConfiguration.getRotation();
if (rotation == ROTATION_UNDEFINED && !isFixedRotationTransforming()) {
rotation = mDisplayContent.getRotation();
}
- if (!mResolveConfigHint.mUseOverrideInsetsForStableBounds
- || getCompatDisplayInsets() != null || isFloating(parentWindowingMode)
- || rotation == ROTATION_UNDEFINED) {
+ if (!mResolveConfigHint.mUseOverrideInsetsForConfig
+ || getCompatDisplayInsets() != null || shouldCreateCompatDisplayInsets()
+ || isFloating(parentWindowingMode) || rotation == ROTATION_UNDEFINED) {
// If the insets configuration decoupled logic is not enabled for the app, or the app
// already has a compat override, or the context doesn't contain enough info to
// calculate the override, skip the override.
@@ -8713,53 +8713,7 @@
}
// Override starts here.
- final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
- final int dw = rotated ? mDisplayContent.mBaseDisplayHeight
- : mDisplayContent.mBaseDisplayWidth;
- final int dh = rotated ? mDisplayContent.mBaseDisplayWidth
- : mDisplayContent.mBaseDisplayHeight;
- final Rect nonDecorInsets = mDisplayContent.getDisplayPolicy()
- .getDecorInsetsInfo(rotation, dw, dh).mOverrideNonDecorInsets;
- // This should be the only place override the configuration for ActivityRecord. Override
- // the value if not calculated yet.
- Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
- if (outAppBounds == null || outAppBounds.isEmpty()) {
- inOutConfig.windowConfiguration.setAppBounds(parentBounds);
- outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
- outAppBounds.inset(nonDecorInsets);
- }
- float density = inOutConfig.densityDpi;
- if (density == Configuration.DENSITY_DPI_UNDEFINED) {
- density = newParentConfiguration.densityDpi;
- }
- density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
- if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
- final int overrideScreenWidthDp = (int) (outAppBounds.width() / density + 0.5f);
- inOutConfig.screenWidthDp = overrideScreenWidthDp;
- }
- if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
- final int overrideScreenHeightDp = (int) (outAppBounds.height() / density + 0.5f);
- inOutConfig.screenHeightDp = overrideScreenHeightDp;
- }
- if (inOutConfig.smallestScreenWidthDp
- == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
- && parentWindowingMode == WINDOWING_MODE_FULLSCREEN) {
- // For the case of PIP transition and multi-window environment, the
- // smallestScreenWidthDp is handled already. Override only if the app is in
- // fullscreen.
- final DisplayInfo info = new DisplayInfo(mDisplayContent.getDisplayInfo());
- mDisplayContent.computeSizeRanges(info, rotated, dw, dh,
- mDisplayContent.getDisplayMetrics().density,
- inOutConfig, true /* overrideConfig */);
- }
-
- // It's possible that screen size will be considered in different orientation with or
- // without considering the system bar insets. Override orientation as well.
- if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
- inOutConfig.orientation =
- (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
- ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
- }
+ computeConfigByResolveHint(inOutConfig, newParentConfiguration);
}
private void computeConfigByResolveHint(@NonNull Configuration resolvedConfig,
@@ -9015,7 +8969,7 @@
if (mDisplayContent == null) {
return true;
}
- if (!mResolveConfigHint.mUseOverrideInsetsForStableBounds) {
+ if (!mResolveConfigHint.mUseOverrideInsetsForConfig) {
// No insets should be considered any more.
return true;
}
@@ -9034,7 +8988,7 @@
final Task task = getTask();
task.calculateInsetFrames(outNonDecorBounds /* outNonDecorBounds */,
outStableBounds /* outStableBounds */, parentBounds /* bounds */, di,
- mResolveConfigHint.mUseOverrideInsetsForStableBounds);
+ mResolveConfigHint.mUseOverrideInsetsForConfig);
final int orientationWithInsets = outStableBounds.height() >= outStableBounds.width()
? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
// If orientation does not match the orientation with insets applied, then a
@@ -9091,7 +9045,7 @@
getResolvedOverrideConfiguration().windowConfiguration.getBounds();
final int stableBoundsOrientation = stableBounds.width() > stableBounds.height()
? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
- final int parentOrientation = mResolveConfigHint.mUseOverrideInsetsForStableBounds
+ final int parentOrientation = mResolveConfigHint.mUseOverrideInsetsForConfig
? stableBoundsOrientation : newParentConfig.orientation;
// If the activity requires a different orientation (either by override or activityInfo),
@@ -9116,7 +9070,7 @@
return;
}
- final Rect parentAppBounds = mResolveConfigHint.mUseOverrideInsetsForStableBounds
+ final Rect parentAppBounds = mResolveConfigHint.mUseOverrideInsetsForConfig
? outNonDecorBounds : newParentConfig.windowConfiguration.getAppBounds();
// TODO(b/182268157): Explore using only one type of parentBoundsWithInsets, either app
// bounds or stable bounds to unify aspect ratio logic.
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index a444c96..26e4eaa 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -40,6 +40,8 @@
import static android.os.Process.SYSTEM_UID;
import static android.os.UserHandle.USER_NULL;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
@@ -2222,7 +2224,7 @@
static class ConfigOverrideHint {
@Nullable DisplayInfo mTmpOverrideDisplayInfo;
@Nullable ActivityRecord.CompatDisplayInsets mTmpCompatInsets;
- boolean mUseOverrideInsetsForStableBounds;
+ boolean mUseOverrideInsetsForConfig;
}
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@@ -2255,11 +2257,11 @@
@NonNull Configuration parentConfig, @Nullable ConfigOverrideHint overrideHint) {
DisplayInfo overrideDisplayInfo = null;
ActivityRecord.CompatDisplayInsets compatInsets = null;
- boolean useOverrideInsetsForStableBounds = false;
+ boolean useOverrideInsetsForConfig = false;
if (overrideHint != null) {
overrideDisplayInfo = overrideHint.mTmpOverrideDisplayInfo;
compatInsets = overrideHint.mTmpCompatInsets;
- useOverrideInsetsForStableBounds = overrideHint.mUseOverrideInsetsForStableBounds;
+ useOverrideInsetsForConfig = overrideHint.mUseOverrideInsetsForConfig;
if (overrideDisplayInfo != null) {
// Make sure the screen related configs can be computed by the provided
// display info.
@@ -2323,6 +2325,7 @@
}
}
+ boolean insetsOverrideApplied = false;
if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
|| inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
if (!customContainerPolicy && WindowConfiguration.isFloating(windowingMode)) {
@@ -2339,7 +2342,7 @@
// The non decor inset are areas that could never be removed in Honeycomb. See
// {@link WindowManagerPolicy#getNonDecorInsetsLw}.
calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di,
- useOverrideInsetsForStableBounds);
+ useOverrideInsetsForConfig);
} else {
// Apply the given non-decor and stable insets to calculate the corresponding bounds
// for screen size of configuration.
@@ -2356,8 +2359,21 @@
intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
compatInsets.mStableInsets[rotation]);
outAppBounds.set(mTmpNonDecorBounds);
+ } else if (useOverrideInsetsForConfig) {
+ final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
+ final int dw = rotated ? mDisplayContent.mBaseDisplayHeight
+ : mDisplayContent.mBaseDisplayWidth;
+ final int dh = rotated ? mDisplayContent.mBaseDisplayWidth
+ : mDisplayContent.mBaseDisplayHeight;
+ final DisplayPolicy.DecorInsets.Info decorInsets = mDisplayContent
+ .getDisplayPolicy().getDecorInsetsInfo(rotation, dw, dh);
+ mTmpStableBounds.set(outAppBounds);
+ mTmpStableBounds.inset(decorInsets.mOverrideConfigInsets);
+ outAppBounds.inset(decorInsets.mOverrideNonDecorInsets);
+ mTmpNonDecorBounds.set(outAppBounds);
+ // Record the override apply to avoid duplicated check.
+ insetsOverrideApplied = true;
} else {
- // Set to app bounds because it excludes decor insets.
mTmpNonDecorBounds.set(outAppBounds);
mTmpStableBounds.set(outAppBounds);
}
@@ -2399,6 +2415,11 @@
// from the parent task would result in applications loaded wrong resource.
inOutConfig.smallestScreenWidthDp =
Math.min(inOutConfig.screenWidthDp, inOutConfig.screenHeightDp);
+ } else if (insetsOverrideApplied) {
+ // The smallest width should also consider insets. If the insets are overridden,
+ // use the overridden value.
+ inOutConfig.smallestScreenWidthDp =
+ Math.min(inOutConfig.screenWidthDp, inOutConfig.screenHeightDp);
}
// otherwise, it will just inherit
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 74ca9ad..97f1e19 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -122,7 +122,6 @@
jmethodID interceptMotionBeforeQueueingNonInteractive;
jmethodID interceptKeyBeforeDispatching;
jmethodID dispatchUnhandledKey;
- jmethodID onPointerDisplayIdChanged;
jmethodID onPointerDownOutsideFocus;
jmethodID getVirtualKeyQuietTimeMillis;
jmethodID getExcludedDeviceNames;
@@ -786,12 +785,6 @@
} // release lock
mInputManager->getReader().requestRefreshConfiguration(
InputReaderConfiguration::Change::DISPLAY_INFO);
-
- // Notify the system.
- JNIEnv* env = jniEnv();
- env->CallVoidMethod(mServiceObj, gServiceClassInfo.onPointerDisplayIdChanged, pointerDisplayId,
- position.x, position.y);
- checkAndClearExceptionFromCallback(env, "onPointerDisplayIdChanged");
}
void NativeInputManager::notifyStickyModifierStateChanged(uint32_t modifierState,
@@ -2933,9 +2926,6 @@
"dispatchUnhandledKey",
"(Landroid/os/IBinder;Landroid/view/KeyEvent;I)Landroid/view/KeyEvent;");
- GET_METHOD_ID(gServiceClassInfo.onPointerDisplayIdChanged, clazz, "onPointerDisplayIdChanged",
- "(IFF)V");
-
GET_METHOD_ID(gServiceClassInfo.notifyStickyModifierStateChanged, clazz,
"notifyStickyModifierStateChanged", "(II)V");
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java
index d29bf1a..3635e9a 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.BatteryManager;
@@ -49,9 +50,9 @@
private static final int BATTERY_CHARGE_RATE_SECONDS_PER_LEVEL = 100;
private MockClock mMockClock;
+ private BatteryStatsImpl.BatteryStatsConfig mConfig;
private MockBatteryStatsImpl mBatteryStatsImpl;
-
/**
* Battery status. Must be one of the following:
* {@link BatteryManager#BATTERY_STATUS_UNKNOWN}
@@ -91,8 +92,9 @@
@Before
public void setUp() throws IOException {
+ mConfig = mock(BatteryStatsImpl.BatteryStatsConfig.class);
mMockClock = new MockClock();
- mBatteryStatsImpl = new MockBatteryStatsImpl(mMockClock,
+ mBatteryStatsImpl = new MockBatteryStatsImpl(mConfig, mMockClock,
Files.createTempDirectory("BatteryStatsResetTest").toFile());
mBatteryStatsImpl.onSystemReady(mock(Context.class));
@@ -110,10 +112,7 @@
@Test
public void testResetOnUnplug_highBatteryLevel() {
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugHighBatteryLevel(true)
- .build());
+ when(mConfig.shouldResetOnUnplugHighBatteryLevel()).thenReturn(true);
long expectedResetTimeUs = 0;
@@ -137,10 +136,7 @@
assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
// disable high battery level reset on unplug.
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugHighBatteryLevel(false)
- .build());
+ when(mConfig.shouldResetOnUnplugHighBatteryLevel()).thenReturn(false);
dischargeToLevel(60);
@@ -153,10 +149,7 @@
@Test
public void testResetOnUnplug_significantCharge() {
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugAfterSignificantCharge(true)
- .build());
+ when(mConfig.shouldResetOnUnplugAfterSignificantCharge()).thenReturn(true);
long expectedResetTimeUs = 0;
unplugBattery();
@@ -186,10 +179,7 @@
assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs);
// disable reset on unplug after significant charge.
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugAfterSignificantCharge(false)
- .build());
+ when(mConfig.shouldResetOnUnplugAfterSignificantCharge()).thenReturn(false);
// Battery level dropped below 20%.
dischargeToLevel(15);
@@ -256,11 +246,9 @@
@Test
public void testResetWhilePluggedIn_longPlugIn() {
// disable high battery level reset on unplug.
- mBatteryStatsImpl.setBatteryStatsConfig(
- new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setResetOnUnplugHighBatteryLevel(false)
- .setResetOnUnplugAfterSignificantCharge(false)
- .build());
+ when(mConfig.shouldResetOnUnplugHighBatteryLevel()).thenReturn(false);
+ when(mConfig.shouldResetOnUnplugAfterSignificantCharge()).thenReturn(false);
+
long expectedResetTimeUs = 0;
plugBattery(BatteryManager.BATTERY_PLUGGED_USB);
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
index 2d7cb22..6edfede 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
@@ -98,10 +98,12 @@
mFreqsByPolicy.put(0, new int[]{300000, 1000000, 2000000});
mFreqsByPolicy.put(4, new int[]{300000, 1000000, 2500000, 3000000});
mBatteryStatsConfigBuilder = new BatteryStatsImpl.BatteryStatsConfig.Builder()
- .setPowerStatsThrottlePeriodMillis(BatteryConsumer.POWER_COMPONENT_CPU,
- 10000)
- .setPowerStatsThrottlePeriodMillis(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
- 10000);
+ .setPowerStatsThrottlePeriodMillis(
+ BatteryConsumer.powerComponentIdToString(
+ BatteryConsumer.POWER_COMPONENT_CPU), 10000)
+ .setPowerStatsThrottlePeriodMillis(
+ BatteryConsumer.powerComponentIdToString(
+ BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO), 10000);
}
private void initBatteryStats() {
@@ -290,7 +292,8 @@
public BatteryUsageStatsRule setPowerStatsThrottlePeriodMillis(int powerComponent,
long throttleMs) {
- mBatteryStatsConfigBuilder.setPowerStatsThrottlePeriodMillis(powerComponent, throttleMs);
+ mBatteryStatsConfigBuilder.setPowerStatsThrottlePeriodMillis(
+ BatteryConsumer.powerComponentIdToString(powerComponent), throttleMs);
return this;
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java
index b5bdafe..d1105a4 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java
@@ -129,6 +129,11 @@
}
@Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return 0;
+ }
+
+ @Override
public int getDefaultCpuPowerBrackets() {
return mDefaultCpuPowerBrackets;
}
@@ -418,8 +423,8 @@
private CpuPowerStatsCollector createCollector(int defaultCpuPowerBrackets,
int defaultCpuPowerBracketsPerEnergyConsumer) {
CpuPowerStatsCollector collector = new CpuPowerStatsCollector(
- new TestInjector(defaultCpuPowerBrackets, defaultCpuPowerBracketsPerEnergyConsumer),
- 0);
+ new TestInjector(defaultCpuPowerBrackets, defaultCpuPowerBracketsPerEnergyConsumer)
+ );
collector.addConsumer(stats -> mCollectedStats = stats);
collector.setEnabled(true);
return collector;
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsCollectorTest.java
index ca58db1..0275319 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsCollectorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsCollectorTest.java
@@ -123,6 +123,11 @@
}
@Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return 0;
+ }
+
+ @Override
public PackageManager getPackageManager() {
return mPackageManager;
}
@@ -348,7 +353,7 @@
}
private PowerStats collectPowerStats(boolean perNetworkTypeData) throws Throwable {
- MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector, 0);
+ MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector);
collector.setEnabled(true);
when(mConsumedEnergyRetriever.getEnergyConsumerIds(
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsProcessorTest.java
index d80ffb4..29ef3b6 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsProcessorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsProcessorTest.java
@@ -114,6 +114,11 @@
}
@Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return 0;
+ }
+
+ @Override
public PackageManager getPackageManager() {
return mPackageManager;
}
@@ -186,7 +191,7 @@
aggregatedStats.setUidState(APP_UID, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND, 0);
aggregatedStats.setUidState(APP_UID2, STATE_PROCESS_STATE, PROCESS_STATE_CACHED, 0);
- MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector, 0);
+ MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector);
collector.setEnabled(true);
// Initial empty ModemActivityInfo.
@@ -425,7 +430,7 @@
aggregatedStats.setUidState(APP_UID, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND, 0);
aggregatedStats.setUidState(APP_UID2, STATE_PROCESS_STATE, PROCESS_STATE_CACHED, 0);
- MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector, 0);
+ MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector);
collector.setEnabled(true);
// Initial empty ModemActivityInfo.
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
index 1d48975..2c03f9d 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
@@ -72,6 +72,11 @@
this(DEFAULT_CONFIG, clock, historyDirectory, handler, new PowerStatsUidResolver());
}
+ MockBatteryStatsImpl(BatteryStatsConfig config, Clock clock, File historyDirectory) {
+ this(config, clock, historyDirectory, new Handler(Looper.getMainLooper()),
+ new PowerStatsUidResolver());
+ }
+
MockBatteryStatsImpl(BatteryStatsConfig config, Clock clock, File historyDirectory,
Handler handler, PowerStatsUidResolver powerStatsUidResolver) {
super(config, clock, new MonotonicClock(0, clock), historyDirectory, handler,
@@ -137,13 +142,6 @@
return MOBILE_RADIO_POWER_STATE_UPDATE_FREQ_MS;
}
- public MockBatteryStatsImpl setBatteryStatsConfig(BatteryStatsConfig config) {
- synchronized (this) {
- mBatteryStatsConfig = config;
- }
- return this;
- }
-
public MockBatteryStatsImpl setNetworkStats(NetworkStats networkStats) {
mNetworkStats = networkStats;
return this;
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PhoneCallPowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PhoneCallPowerStatsProcessorTest.java
index dadcf3f..69d655b 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/PhoneCallPowerStatsProcessorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PhoneCallPowerStatsProcessorTest.java
@@ -98,6 +98,11 @@
}
@Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return 0;
+ }
+
+ @Override
public PackageManager getPackageManager() {
return mPackageManager;
}
@@ -175,7 +180,7 @@
aggregatedPowerStats.setDeviceState(STATE_POWER, POWER_STATE_OTHER, 0);
aggregatedPowerStats.setDeviceState(STATE_SCREEN, SCREEN_STATE_ON, 0);
- MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector, 0);
+ MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector);
collector.setEnabled(true);
// Initial empty ModemActivityInfo.
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java
index b4c012b..a280cfe 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java
@@ -138,6 +138,11 @@
}
@Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return 0;
+ }
+
+ @Override
public PackageManager getPackageManager() {
return mPackageManager;
}
@@ -317,7 +322,7 @@
private PowerStats collectPowerStats(boolean hasPowerReporting) {
when(mWifiManager.isEnhancedPowerReportingSupported()).thenReturn(hasPowerReporting);
- WifiPowerStatsCollector collector = new WifiPowerStatsCollector(mInjector, 0);
+ WifiPowerStatsCollector collector = new WifiPowerStatsCollector(mInjector);
collector.setEnabled(true);
when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.WIFI))
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsProcessorTest.java
index 257a1a6..3ceaf35 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsProcessorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsProcessorTest.java
@@ -142,6 +142,11 @@
}
@Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return 0;
+ }
+
+ @Override
public PackageManager getPackageManager() {
return mPackageManager;
}
@@ -195,7 +200,7 @@
PowerComponentAggregatedPowerStats aggregatedStats = createAggregatedPowerStats(processor);
- WifiPowerStatsCollector collector = new WifiPowerStatsCollector(mInjector, 0);
+ WifiPowerStatsCollector collector = new WifiPowerStatsCollector(mInjector);
collector.setEnabled(true);
// Initial empty WifiActivityEnergyInfo.
@@ -307,7 +312,7 @@
PowerComponentAggregatedPowerStats aggregatedStats = createAggregatedPowerStats(processor);
- WifiPowerStatsCollector collector = new WifiPowerStatsCollector(mInjector, 0);
+ WifiPowerStatsCollector collector = new WifiPowerStatsCollector(mInjector);
collector.setEnabled(true);
// Initial empty WifiActivityEnergyInfo.
@@ -420,7 +425,7 @@
PowerComponentAggregatedPowerStats aggregatedStats = createAggregatedPowerStats(processor);
- WifiPowerStatsCollector collector = new WifiPowerStatsCollector(mInjector, 0);
+ WifiPowerStatsCollector collector = new WifiPowerStatsCollector(mInjector);
collector.setEnabled(true);
// Establish a baseline
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index b5f0a52..b50684b 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -26,6 +26,8 @@
import static com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_WAKE_UP_MESSAGE;
+import static com.android.server.hdmi.HdmiControlService.STANDBY_SCREEN_OFF;
+import static com.android.server.hdmi.HdmiControlService.WAKE_UP_SCREEN_ON;
import static com.google.common.truth.Truth.assertThat;
@@ -1780,9 +1782,17 @@
HdmiCecMessage activeSourceFromTv =
HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
- mHdmiControlService.getHdmiCecNetwork().clearLocalDevices();
+ // Go to standby to invalidate the active source on the local device s.t. the
+ // RequestActiveSourceAction will start.
+ mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
- mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
+ mTestLooper.dispatchAll();
+
+ // Skip the LauncherX API timeout.
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS * 2);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
@@ -1791,6 +1801,10 @@
mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
mTestLooper.dispatchAll();
+ // Assume there was a retry and the action did not finish earlier.
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSourceFromTv);
}
@@ -1800,9 +1814,18 @@
HdmiCecMessageBuilder.buildRequestActiveSource(ADDR_TV);
HdmiCecMessage activeSourceFromTv =
HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
- mHdmiControlService.getHdmiCecNetwork().clearLocalDevices();
+
+ // Go to standby to invalidate the active source on the local device s.t. the
+ // RequestActiveSourceAction will start.
+ mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
- mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
+ mTestLooper.dispatchAll();
+
+ // Skip the LauncherX API timeout.
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS * 2);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
@@ -1827,8 +1850,18 @@
HdmiCecMessageBuilder.buildRequestActiveSource(ADDR_TV);
HdmiCecMessage activeSourceFromTv =
HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
- mHdmiControlService.getHdmiCecNetwork().clearLocalDevices();
- mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+
+ // Go to standby to invalidate the active source on the local device s.t. the
+ // RequestActiveSourceAction will start.
+ mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
+ mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
+ mTestLooper.dispatchAll();
+
+ // Skip the LauncherX API timeout.
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS * 2);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
@@ -1847,8 +1880,16 @@
HdmiCecMessageBuilder.buildRequestActiveSource(ADDR_TV);
HdmiCecMessage activeSourceFromTv =
HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
- mHdmiControlService.getHdmiCecNetwork().clearLocalDevices();
- mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+
+ // Go to standby to invalidate the active source on the local device s.t. the
+ // RequestActiveSourceAction will start.
+ mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
+ mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
+ mTestLooper.dispatchAll();
+
HdmiDeviceInfo playbackDevice = HdmiDeviceInfo.cecDeviceBuilder()
.setLogicalAddress(ADDR_PLAYBACK_1)
.setPhysicalAddress(0x1000)
@@ -1862,6 +1903,10 @@
mHdmiControlService.getHdmiCecNetwork().addCecDevice(playbackDevice);
mTestLooper.dispatchAll();
+ // Skip the LauncherX API timeout.
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS * 2);
+ mTestLooper.dispatchAll();
+
assertThat(mNativeWrapper.getResultMessages()).contains(requestActiveSource);
mNativeWrapper.clearResultMessages();
mHdmiCecLocalDeviceTv.deviceSelect(playbackDevice.getId(), null);
@@ -1874,6 +1919,41 @@
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSourceFromTv);
}
+ @Test
+ public void onAddressAllocated_sendSourceChangingMessage_noRequestActiveSourceMessage() {
+ HdmiCecMessage requestActiveSource =
+ HdmiCecMessageBuilder.buildRequestActiveSource(ADDR_TV);
+ HdmiCecMessage activeSourceFromTv =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
+ HdmiCecMessage setStreamPathFromTv =
+ HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x2000);
+
+ // Go to standby to invalidate the active source on the local device s.t. the
+ // RequestActiveSourceAction will start.
+ mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
+ mTestLooper.dispatchAll();
+
+ // Even if the device at the end of this path doesn't answer to this message, TV should not
+ // continue the RequestActiveSourceAction.
+ mHdmiControlService.sendCecCommand(setStreamPathFromTv);
+
+ // Skip the LauncherX API timeout.
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS * 2);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestActiveSource);
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+
+ // Assume there was a retry and the action did not finish earlier.
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSourceFromTv);
+ }
@Test
public void newDeviceConnectedIfOnlyOneGiveOsdNameSent() {
@@ -1900,7 +1980,12 @@
HdmiCecMessage activeSourceFromTv =
HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
- mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_WAKE_UP_MESSAGE);
+ // Go to standby to invalidate the active source on the local device s.t. the
+ // TV will send <Active Source> when it selects its internal source.
+ mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
mTestLooper.dispatchAll();
mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
@@ -1930,6 +2015,8 @@
public void handleStandby_fromActiveSource_standby() {
mPowerManager.setInteractive(true);
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mTestLooper.dispatchAll();
+
mHdmiControlService.setActiveSource(ADDR_PLAYBACK_1, 0x1000,
"HdmiCecLocalDeviceTvTest");
mTestLooper.dispatchAll();
diff --git a/tests/Input/src/android/hardware/input/KeyboardLayoutPreviewTests.kt b/tests/Input/src/android/hardware/input/KeyboardLayoutPreviewTests.kt
index 3a2a3be..ae32bda 100644
--- a/tests/Input/src/android/hardware/input/KeyboardLayoutPreviewTests.kt
+++ b/tests/Input/src/android/hardware/input/KeyboardLayoutPreviewTests.kt
@@ -16,6 +16,8 @@
package android.hardware.input
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.content.ContextWrapper
import android.graphics.drawable.Drawable
import android.platform.test.annotations.Presubmit
@@ -54,16 +56,16 @@
}
@Test
+ @EnableFlags(Flags.FLAG_KEYBOARD_LAYOUT_PREVIEW_FLAG)
fun testKeyboardLayoutDrawable_hasCorrectDimensions() {
- setFlagsRule.enableFlags(Flags.FLAG_KEYBOARD_LAYOUT_PREVIEW_FLAG)
val drawable = createDrawable()!!
assertEquals(WIDTH, drawable.intrinsicWidth)
assertEquals(HEIGHT, drawable.intrinsicHeight)
}
@Test
+ @DisableFlags(Flags.FLAG_KEYBOARD_LAYOUT_PREVIEW_FLAG)
fun testKeyboardLayoutDrawable_isNull_ifFlagOff() {
- setFlagsRule.disableFlags(Flags.FLAG_KEYBOARD_LAYOUT_PREVIEW_FLAG)
assertNull(createDrawable())
}
}
\ No newline at end of file
diff --git a/tests/Input/src/android/hardware/input/StickyModifierStateListenerTest.kt b/tests/Input/src/android/hardware/input/StickyModifierStateListenerTest.kt
index e2b0c36..bcd56ad 100644
--- a/tests/Input/src/android/hardware/input/StickyModifierStateListenerTest.kt
+++ b/tests/Input/src/android/hardware/input/StickyModifierStateListenerTest.kt
@@ -21,6 +21,7 @@
import android.os.Handler
import android.os.HandlerExecutor
import android.os.test.TestLooper
+import android.platform.test.annotations.EnableFlags
import android.platform.test.annotations.Presubmit
import android.platform.test.flag.junit.SetFlagsRule
import android.view.KeyEvent
@@ -50,6 +51,10 @@
*/
@Presubmit
@RunWith(MockitoJUnitRunner::class)
+@EnableFlags(
+ com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_STICKY_KEYS_FLAG,
+ com.android.input.flags.Flags.FLAG_ENABLE_INPUT_FILTER_RUST_IMPL,
+)
class StickyModifierStateListenerTest {
@get:Rule
@@ -67,10 +72,6 @@
@Before
fun setUp() {
- // Enable Sticky keys feature
- rule.enableFlags(com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_STICKY_KEYS_FLAG)
- rule.enableFlags(com.android.input.flags.Flags.FLAG_ENABLE_INPUT_FILTER_RUST_IMPL)
-
context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManagerMock)
inputManager = InputManager(context)
diff --git a/tests/UsbManagerTests/src/android/hardware/usb/DeviceFilterTest.java b/tests/UsbManagerTests/src/android/hardware/usb/DeviceFilterTest.java
new file mode 100644
index 0000000..d6f3148
--- /dev/null
+++ b/tests/UsbManagerTests/src/android/hardware/usb/DeviceFilterTest.java
@@ -0,0 +1,248 @@
+/*
+ * 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 android.hardware.usb;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.hardware.usb.flags.Flags;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.util.XmlUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserFactory;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.StringReader;
+
+/**
+ * Unit tests for {@link android.hardware.usb.DeviceFilter}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class DeviceFilterTest {
+
+ private static final int VID = 10;
+ private static final int PID = 11;
+ private static final int CLASS = 12;
+ private static final int SUBCLASS = 13;
+ private static final int PROTOCOL = 14;
+ private static final String MANUFACTURER = "Google";
+ private static final String PRODUCT = "Test";
+ private static final String SERIAL_NO = "4AL23";
+ private static final String INTERFACE_NAME = "MTP";
+
+ private MockitoSession mStaticMockSession;
+
+ @Before
+ public void setUp() throws Exception {
+ mStaticMockSession = ExtendedMockito.mockitoSession()
+ .mockStatic(Flags.class)
+ .strictness(Strictness.WARN)
+ .startMocking();
+
+ when(Flags.enableInterfaceNameDeviceFilter()).thenReturn(true);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mStaticMockSession.finishMocking();
+ }
+
+ @Test
+ public void testConstructorFromValues_interfaceNameIsInitialized() {
+ DeviceFilter deviceFilter = new DeviceFilter(
+ VID, PID, CLASS, SUBCLASS, PROTOCOL, MANUFACTURER,
+ PRODUCT, SERIAL_NO, INTERFACE_NAME
+ );
+
+ verifyDeviceFilterConfigurationExceptInterfaceName(deviceFilter);
+ assertThat(deviceFilter.mInterfaceName).isEqualTo(INTERFACE_NAME);
+ }
+
+ @Test
+ public void testConstructorFromUsbDevice_interfaceNameIsNull() {
+ UsbDevice usbDevice = Mockito.mock(UsbDevice.class);
+ when(usbDevice.getVendorId()).thenReturn(VID);
+ when(usbDevice.getProductId()).thenReturn(PID);
+ when(usbDevice.getDeviceClass()).thenReturn(CLASS);
+ when(usbDevice.getDeviceSubclass()).thenReturn(SUBCLASS);
+ when(usbDevice.getDeviceProtocol()).thenReturn(PROTOCOL);
+ when(usbDevice.getManufacturerName()).thenReturn(MANUFACTURER);
+ when(usbDevice.getProductName()).thenReturn(PRODUCT);
+ when(usbDevice.getSerialNumber()).thenReturn(SERIAL_NO);
+
+ DeviceFilter deviceFilter = new DeviceFilter(usbDevice);
+
+ verifyDeviceFilterConfigurationExceptInterfaceName(deviceFilter);
+ assertThat(deviceFilter.mInterfaceName).isEqualTo(null);
+ }
+
+ @Test
+ public void testConstructorFromDeviceFilter_interfaceNameIsInitialized() {
+ DeviceFilter originalDeviceFilter = new DeviceFilter(
+ VID, PID, CLASS, SUBCLASS, PROTOCOL, MANUFACTURER,
+ PRODUCT, SERIAL_NO, INTERFACE_NAME
+ );
+
+ DeviceFilter deviceFilter = new DeviceFilter(originalDeviceFilter);
+
+ verifyDeviceFilterConfigurationExceptInterfaceName(deviceFilter);
+ assertThat(deviceFilter.mInterfaceName).isEqualTo(INTERFACE_NAME);
+ }
+
+
+ @Test
+ public void testReadFromXml_interfaceNamePresent_propertyIsInitialized() throws Exception {
+ DeviceFilter deviceFilter = getDeviceFilterFromXml("<usb-device interface-name=\"MTP\"/>");
+
+ assertThat(deviceFilter.mInterfaceName).isEqualTo("MTP");
+ }
+
+ @Test
+ public void testReadFromXml_interfaceNameAbsent_propertyIsNull() throws Exception {
+ DeviceFilter deviceFilter = getDeviceFilterFromXml("<usb-device vendor-id=\"1\" />");
+
+ assertThat(deviceFilter.mInterfaceName).isEqualTo(null);
+ }
+
+ @Test
+ public void testWrite_withInterfaceName() throws Exception {
+ DeviceFilter deviceFilter = getDeviceFilterFromXml("<usb-device interface-name=\"MTP\"/>");
+ XmlSerializer serializer = Mockito.mock(XmlSerializer.class);
+
+ deviceFilter.write(serializer);
+
+ verify(serializer).attribute(null, "interface-name", "MTP");
+ }
+
+ @Test
+ public void testWrite_withoutInterfaceName() throws Exception {
+ DeviceFilter deviceFilter = getDeviceFilterFromXml("<usb-device vendor-id=\"1\" />");
+ XmlSerializer serializer = Mockito.mock(XmlSerializer.class);
+
+ deviceFilter.write(serializer);
+
+ verify(serializer, times(0)).attribute(eq(null), eq("interface-name"), any());
+ }
+
+ @Test
+ public void testToString() {
+ DeviceFilter deviceFilter = new DeviceFilter(
+ VID, PID, CLASS, SUBCLASS, PROTOCOL, MANUFACTURER,
+ PRODUCT, SERIAL_NO, INTERFACE_NAME
+ );
+
+ assertThat(deviceFilter.toString()).isEqualTo(
+ "DeviceFilter[mVendorId=10,mProductId=11,mClass=12,mSubclass=13,mProtocol=14,"
+ + "mManufacturerName=Google,mProductName=Test,mSerialNumber=4AL23,"
+ + "mInterfaceName=MTP]");
+ }
+
+ @Test
+ public void testMatch_interfaceNameMatches_returnTrue() throws Exception {
+ DeviceFilter deviceFilter = getDeviceFilterFromXml(
+ "<usb-device class=\"255\" subclass=\"255\" protocol=\"0\" "
+ + "interface-name=\"MTP\"/>");
+ UsbDevice usbDevice = Mockito.mock(UsbDevice.class);
+ when(usbDevice.getInterfaceCount()).thenReturn(1);
+ when(usbDevice.getInterface(0)).thenReturn(new UsbInterface(
+ /* id= */ 0,
+ /* alternateSetting= */ 0,
+ /* name= */ "MTP",
+ /* class= */ 255,
+ /* subClass= */ 255,
+ /* protocol= */ 0));
+
+ assertTrue(deviceFilter.matches(usbDevice));
+ }
+
+ @Test
+ public void testMatch_interfaceNameMismatch_returnFalse() throws Exception {
+ DeviceFilter deviceFilter = getDeviceFilterFromXml(
+ "<usb-device class=\"255\" subclass=\"255\" protocol=\"0\" "
+ + "interface-name=\"MTP\"/>");
+ UsbDevice usbDevice = Mockito.mock(UsbDevice.class);
+ when(usbDevice.getInterfaceCount()).thenReturn(1);
+ when(usbDevice.getInterface(0)).thenReturn(new UsbInterface(
+ /* id= */ 0,
+ /* alternateSetting= */ 0,
+ /* name= */ "UVC",
+ /* class= */ 255,
+ /* subClass= */ 255,
+ /* protocol= */ 0));
+
+ assertFalse(deviceFilter.matches(usbDevice));
+ }
+
+ @Test
+ public void testMatch_interfaceNameMismatchFlagDisabled_returnTrue() throws Exception {
+ when(Flags.enableInterfaceNameDeviceFilter()).thenReturn(false);
+ DeviceFilter deviceFilter = getDeviceFilterFromXml(
+ "<usb-device class=\"255\" subclass=\"255\" protocol=\"0\" "
+ + "interface-name=\"MTP\"/>");
+ UsbDevice usbDevice = Mockito.mock(UsbDevice.class);
+ when(usbDevice.getInterfaceCount()).thenReturn(1);
+ when(usbDevice.getInterface(0)).thenReturn(new UsbInterface(
+ /* id= */ 0,
+ /* alternateSetting= */ 0,
+ /* name= */ "UVC",
+ /* class= */ 255,
+ /* subClass= */ 255,
+ /* protocol= */ 0));
+
+ assertTrue(deviceFilter.matches(usbDevice));
+ }
+
+ private void verifyDeviceFilterConfigurationExceptInterfaceName(DeviceFilter deviceFilter) {
+ assertThat(deviceFilter.mVendorId).isEqualTo(VID);
+ assertThat(deviceFilter.mProductId).isEqualTo(PID);
+ assertThat(deviceFilter.mClass).isEqualTo(CLASS);
+ assertThat(deviceFilter.mSubclass).isEqualTo(SUBCLASS);
+ assertThat(deviceFilter.mProtocol).isEqualTo(PROTOCOL);
+ assertThat(deviceFilter.mManufacturerName).isEqualTo(MANUFACTURER);
+ assertThat(deviceFilter.mProductName).isEqualTo(PRODUCT);
+ assertThat(deviceFilter.mSerialNumber).isEqualTo(SERIAL_NO);
+ }
+
+ private DeviceFilter getDeviceFilterFromXml(String xml) throws Exception {
+ XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+ XmlPullParser parser = factory.newPullParser();
+ parser.setInput(new StringReader(xml));
+ XmlUtils.nextElement(parser);
+
+ return DeviceFilter.read(parser);
+ }
+
+}