diff options
223 files changed, 4508 insertions, 1987 deletions
diff --git a/Android.bp b/Android.bp index 14b5b309ebdf..20ca1b7c1020 100644 --- a/Android.bp +++ b/Android.bp @@ -344,8 +344,8 @@ filegroup { genrule { name: "statslog-telephony-common-java-gen", tools: ["stats-log-api-gen"], - cmd: "$(location stats-log-api-gen) --java $(out) --module telephony_common" + - " --javaPackage com.android.internal.telephony --javaClass TelephonyCommonStatsLog", + cmd: "$(location stats-log-api-gen) --java $(out) --module telephony_common" + + " --javaPackage com.android.internal.telephony --javaClass TelephonyCommonStatsLog", out: ["com/android/internal/telephony/TelephonyCommonStatsLog.java"], } @@ -421,6 +421,7 @@ filegroup { ":resourcemanager_aidl", ":storaged_aidl", ":vold_aidl", + ":deviceproductinfoconstants_aidl", // For the generated R.java and Manifest.java ":framework-res{.aapt.srcjar}", @@ -749,8 +750,8 @@ java_library { } platform_compat_config { - name: "framework-platform-compat-config", - src: ":framework-minus-apex", + name: "framework-platform-compat-config", + src: ":framework-minus-apex", } // A temporary build target that is conditionally included on the bootclasspath if @@ -771,7 +772,7 @@ genrule { name: "statslog-framework-java-gen", tools: ["stats-log-api-gen"], cmd: "$(location stats-log-api-gen) --java $(out) --module framework" + - " --javaPackage com.android.internal.util --javaClass FrameworkStatsLog --worksource", + " --javaPackage com.android.internal.util --javaClass FrameworkStatsLog --worksource", out: ["com/android/internal/util/FrameworkStatsLog.java"], } @@ -880,7 +881,7 @@ filegroup { java_library { name: "framework-annotations-lib", - srcs: [":framework-annotations"], + srcs: [ ":framework-annotations" ], sdk_version: "core_current", } @@ -1158,6 +1159,7 @@ cc_library { }, } + // This is the full proto version of libplatformprotos. It may only // be used by test code that is not shipped on the device. cc_library { @@ -1223,58 +1225,68 @@ filegroup { path: "core/java", } -cc_defaults { - name: "incremental_default", - host_supported: true, - cflags: [ - "-Wall", - "-Wextra", - "-Wextra-semi", - "-Werror", - "-Wzero-as-null-pointer-constant", - "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION", - ], - shared_libs: [ - "libbinder", - "libutils", - ], - aidl: { - include_dirs: [ - "frameworks/native/aidl/binder", - ], - export_aidl_headers: true, - }, -} - -cc_library { - name: "libincremental_aidl-cpp", +aidl_interface { + name: "libincremental_aidl", + unstable: true, srcs: [ ":incremental_aidl", ], - defaults: ["incremental_default"], + backend: { + java: { + sdk_version: "28", + }, + cpp: { + enabled: true, + }, + ndk: { + enabled: true, + }, + }, } -cc_library { - name: "libdataloader_aidl-cpp", +aidl_interface { + name: "libdataloader_aidl", + unstable: true, srcs: [ ":dataloader_aidl", ], - defaults: ["incremental_default"], - shared_libs: [ - "libincremental_aidl-cpp", + imports: [ + "libincremental_aidl", ], + backend: { + java: { + sdk_version: "28", + }, + cpp: { + enabled: true, + }, + ndk: { + enabled: false, + }, + }, } -cc_library { - name: "libincremental_manager_aidl-cpp", +aidl_interface { + name: "libincremental_manager_aidl", + unstable: true, srcs: [ ":incremental_manager_aidl", ], - defaults: ["incremental_default"], - shared_libs: [ - "libincremental_aidl-cpp", - "libdataloader_aidl-cpp", + imports: [ + "libincremental_aidl", + "libdataloader_aidl", ], + backend: { + java: { + sdk_version: "28", + }, + cpp: { + enabled: true, + }, + ndk: { + enabled: false, + }, + }, } // TODO(b/77285514): remove this once the last few hidl interfaces have been @@ -1303,7 +1315,7 @@ java_library { "core/java/android/os/RemoteException.java", "core/java/android/util/AndroidException.java", ], - libs: ["unsupportedappusage"], + libs: [ "unsupportedappusage" ], dxflags: ["--core-library"], installable: false, @@ -1522,5 +1534,4 @@ java_library { ":protolog-common-src", ], } - // protolog end diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 175fb38bafc7..30ed7de92614 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -1,6 +1,5 @@ [Builtin Hooks] clang_format = true -bpfmt = true [Builtin Hooks Options] # Only turn on clang-format check for the following subfolders. @@ -16,7 +15,7 @@ clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp services/incremental/ tests/ tools/ -bpfmt = -d + [Hook Scripts] checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT} diff --git a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt b/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt index 1d94d7e8eca2..d5ed95f18f93 100644 --- a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt +++ b/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt @@ -97,11 +97,21 @@ class PackageParsingPerfTest { private val state: BenchmarkState get() = perfStatusReporter.benchmarkState private val apks: List<File> get() = params.apks + private fun safeParse(parser: ParallelParser<*>, file: File) { + try { + parser.parse(file) + } catch (e: Exception) { + // ignore + } + } + @Test fun sequentialNoCache() { params.cacheDirToParser(null).use { parser -> while (state.keepRunning()) { - apks.forEach { parser.parse(it) } + apks.forEach { + safeParse(parser, it) + } } } } @@ -110,10 +120,10 @@ class PackageParsingPerfTest { fun sequentialCached() { params.cacheDirToParser(testFolder.newFolder()).use { parser -> // Fill the cache - apks.forEach { parser.parse(it) } + apks.forEach { safeParse(parser, it) } while (state.keepRunning()) { - apks.forEach { parser.parse(it) } + apks.forEach { safeParse(parser, it) } } } } @@ -132,7 +142,7 @@ class PackageParsingPerfTest { fun parallelCached() { params.cacheDirToParser(testFolder.newFolder()).use { parser -> // Fill the cache - apks.forEach { parser.parse(it) } + apks.forEach { safeParse(parser, it) } while (state.keepRunning()) { apks.forEach { parser.submit(it) } diff --git a/core/api/current.txt b/core/api/current.txt index f1b9cef113cc..4f1235c54b7c 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -18569,6 +18569,23 @@ package android.hardware.camera2.params { package android.hardware.display { + public final class DeviceProductInfo implements android.os.Parcelable { + method public int describeContents(); + method public int getConnectionToSinkType(); + method public int getManufactureWeek(); + method public int getManufactureYear(); + method @NonNull public String getManufacturerPnpId(); + method public int getModelYear(); + method @Nullable public String getName(); + method @NonNull public String getProductId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int CONNECTION_TO_SINK_BUILT_IN = 1; // 0x1 + field public static final int CONNECTION_TO_SINK_DIRECT = 2; // 0x2 + field public static final int CONNECTION_TO_SINK_TRANSITIVE = 3; // 0x3 + field public static final int CONNECTION_TO_SINK_UNKNOWN = 0; // 0x0 + field @NonNull public static final android.os.Parcelable.Creator<android.hardware.display.DeviceProductInfo> CREATOR; + } + public final class DisplayManager { method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int); method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int, @Nullable android.hardware.display.VirtualDisplay.Callback, @Nullable android.os.Handler); @@ -25870,6 +25887,7 @@ package android.net { method @NonNull public static java.util.Set<java.lang.String> getSupportedAlgorithms(); method public int getTruncationLengthBits(); method public void writeToParcel(android.os.Parcel, int); + field public static final String AUTH_AES_CMAC = "cmac(aes)"; field public static final String AUTH_AES_XCBC = "xcbc(aes)"; field public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))"; field public static final String AUTH_CRYPT_CHACHA20_POLY1305 = "rfc7539esp(chacha20,poly1305)"; @@ -26011,6 +26029,16 @@ package android.net { field public static final int TYPE_IKEV2_IPSEC_USER_PASS = 6; // 0x6 } + public final class Proxy { + ctor public Proxy(); + method @Deprecated public static String getDefaultHost(); + method @Deprecated public static int getDefaultPort(); + method @Deprecated public static String getHost(android.content.Context); + method @Deprecated public static int getPort(android.content.Context); + field @Deprecated public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO"; + field public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE"; + } + @Deprecated public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory { ctor @Deprecated public SSLCertificateSocketFactory(int); method @Deprecated public java.net.Socket createSocket(java.net.Socket, String, int, boolean) throws java.io.IOException; @@ -41316,7 +41344,6 @@ package android.telephony { method @NonNull public java.util.List<java.lang.Integer> getAvailableServices(); method @Nullable public android.telephony.CellIdentity getCellIdentity(); method public int getDomain(); - method public int getNrState(); method @Nullable public String getRegisteredPlmn(); method public int getTransportType(); method public boolean isRegistered(); @@ -45852,7 +45879,7 @@ package android.util { method public void clear(); method public android.util.SparseArray<E> clone(); method public boolean contains(int); - method public boolean contentEquals(@Nullable android.util.SparseArray<E>); + method public boolean contentEquals(@Nullable android.util.SparseArray<?>); method public int contentHashCode(); method public void delete(int); method public E get(int); @@ -46248,6 +46275,7 @@ package android.view { method public long getAppVsyncOffsetNanos(); method public void getCurrentSizeRange(android.graphics.Point, android.graphics.Point); method @Nullable public android.view.DisplayCutout getCutout(); + method @Nullable public android.hardware.display.DeviceProductInfo getDeviceProductInfo(); method public int getDisplayId(); method public int getFlags(); method public android.view.Display.HdrCapabilities getHdrCapabilities(); diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 7ea7d61ac3c5..60325b3cbd37 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -167,10 +167,26 @@ package android.net { method public int getResourceId(); } + public final class NetworkStateSnapshot implements android.os.Parcelable { + ctor public NetworkStateSnapshot(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @Nullable String, int); + method public int describeContents(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStateSnapshot> CREATOR; + field public final int legacyType; + field @NonNull public final android.net.LinkProperties linkProperties; + field @NonNull public final android.net.Network network; + field @NonNull public final android.net.NetworkCapabilities networkCapabilities; + field @Nullable public final String subscriberId; + } + public class NetworkWatchlistManager { method @Nullable public byte[] getWatchlistConfigHash(); } + public final class Proxy { + method public static void setHttpProxyConfiguration(@Nullable android.net.ProxyInfo); + } + public final class UnderlyingNetworkInfo implements android.os.Parcelable { ctor public UnderlyingNetworkInfo(int, @NonNull String, @NonNull java.util.List<java.lang.String>); method public int describeContents(); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index c7744a415db5..02925c59bf61 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2552,8 +2552,7 @@ package android.content.pm { field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio"; field public static final String FEATURE_CAMERA_TOGGLE = "android.hardware.camera.toggle"; field public static final String FEATURE_CONTEXT_HUB = "android.hardware.context_hub"; - field @Deprecated public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery"; - field public static final String FEATURE_INCREMENTAL_DELIVERY_VERSION = "android.software.incremental_delivery_version"; + field public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery"; field public static final String FEATURE_MICROPHONE_TOGGLE = "android.hardware.microphone.toggle"; field public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow"; field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock"; @@ -7151,9 +7150,6 @@ package android.net { method public abstract void onRequestScores(android.net.NetworkKey[]); } - public class NetworkReleasedException extends java.lang.Exception { - } - public class NetworkScoreManager { method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public boolean clearScores() throws java.lang.SecurityException; method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public void disableScoring() throws java.lang.SecurityException; @@ -7237,47 +7233,6 @@ package android.net { method @NonNull public android.net.OemNetworkPreferences.Builder clearNetworkPreference(@NonNull String); } - public abstract class QosCallback { - ctor public QosCallback(); - method public void onError(@NonNull android.net.QosCallbackException); - method public void onQosSessionAvailable(@NonNull android.net.QosSession, @NonNull android.net.QosSessionAttributes); - method public void onQosSessionLost(@NonNull android.net.QosSession); - } - - public static class QosCallback.QosCallbackRegistrationException extends java.lang.RuntimeException { - } - - public final class QosCallbackException extends java.lang.Exception { - } - - public abstract class QosFilter { - method @NonNull public abstract android.net.Network getNetwork(); - method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int); - } - - public final class QosSession implements android.os.Parcelable { - ctor public QosSession(int, int); - method public int describeContents(); - method public int getSessionId(); - method public int getSessionType(); - method public long getUniqueId(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR; - field public static final int TYPE_EPS_BEARER = 1; // 0x1 - } - - public interface QosSessionAttributes { - } - - public final class QosSocketInfo implements android.os.Parcelable { - ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.Socket) throws java.io.IOException; - method public int describeContents(); - method @NonNull public java.net.InetSocketAddress getLocalSocketAddress(); - method @NonNull public android.net.Network getNetwork(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR; - } - public class RssiCurve implements android.os.Parcelable { ctor public RssiCurve(int, int, byte[]); ctor public RssiCurve(int, int, byte[], int); @@ -7309,12 +7264,6 @@ package android.net { field public final android.net.RssiCurve rssiCurve; } - public class SocketLocalAddressChangedException extends java.lang.Exception { - } - - public class SocketNotBoundException extends java.lang.Exception { - } - public class TrafficStats { method public static void setThreadStatsTagApp(); method public static void setThreadStatsTagBackup(); @@ -7544,6 +7493,19 @@ package android.net.sip { } +package android.net.util { + + public final class SocketUtils { + method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException; + method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException; + method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int); + method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int); + method @Deprecated @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]); + method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int, @NonNull byte[]); + } + +} + package android.net.vcn { public class VcnManager { diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 76295545ad17..1e5a6f12f96b 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -399,6 +399,8 @@ package android.app.admin { method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public void forceRemoveActiveAdmin(@NonNull android.content.ComponentName, int); method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceSecurityLogs(); method public void forceUpdateUserSetupComplete(); + method @NonNull public java.util.Set<java.lang.String> getDefaultCrossProfilePackages(); + method @NonNull public java.util.Set<java.lang.String> getDisallowedSystemApps(@NonNull android.content.ComponentName, int, @NonNull String); method public long getLastBugReportRequestTime(); method public long getLastNetworkLogRetrievalTime(); method public long getLastSecurityLogRetrievalTime(); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index cc2d36379c88..f5f0b422a69d 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -7119,6 +7119,9 @@ public class Activity extends ContextThemeWrapper case "--contentcapture": dumpContentCaptureManager(prefix, writer); return; + case "--translation": + dumpUiTranslation(prefix, writer); + return; } } writer.print(prefix); writer.print("Local Activity "); @@ -7159,6 +7162,7 @@ public class Activity extends ContextThemeWrapper dumpAutofillManager(prefix, writer); dumpContentCaptureManager(prefix, writer); + dumpUiTranslation(prefix, writer); ResourcesManager.getInstance().dump(prefix, writer); } @@ -7183,6 +7187,14 @@ public class Activity extends ContextThemeWrapper } } + void dumpUiTranslation(String prefix, PrintWriter writer) { + if (mUiTranslationController != null) { + mUiTranslationController.dump(prefix, writer); + } else { + writer.print(prefix); writer.println("No UiTranslationController"); + } + } + /** * Bit indicating that this activity is "immersive" and should not be * interrupted by notifications if possible. diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index bb1ff6051d56..b919bfc92e79 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -12239,8 +12239,9 @@ public class DevicePolicyManager { * * @hide */ - public Set<String> getDisallowedSystemApps(ComponentName admin, int userId, - String provisioningAction) { + @TestApi + public @NonNull Set<String> getDisallowedSystemApps(@NonNull ComponentName admin, + @UserIdInt int userId, @NonNull String provisioningAction) { try { return new ArraySet<>( mService.getDisallowedSystemApps(admin, userId, provisioningAction)); @@ -13004,6 +13005,7 @@ public class DevicePolicyManager { * * @hide */ + @TestApi public @NonNull Set<String> getDefaultCrossProfilePackages() { throwIfParentInstance("getDefaultCrossProfilePackages"); if (mService != null) { diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 3bc61444f1d1..7b62f3b2f1a2 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3584,30 +3584,18 @@ public abstract class PackageManager { * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has * the requisite kernel support to support incremental delivery aka Incremental FileSystem. * - * @see IncrementalManager#isFeatureEnabled - * @hide - * - * @deprecated Use {@link #FEATURE_INCREMENTAL_DELIVERY_VERSION} instead. - */ - @Deprecated - @SystemApi - @SdkConstant(SdkConstantType.FEATURE) - public static final String FEATURE_INCREMENTAL_DELIVERY = - "android.software.incremental_delivery"; - - /** - * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: * feature not present - IncFs is not present on the device. * 1 - IncFs v1, core features, no PerUid support. Optional in R. * 2 - IncFs v2, PerUid support, fs-verity support. Required in S. * + * @see IncrementalManager#isFeatureEnabled * @see IncrementalManager#getVersion() * @hide */ @SystemApi @SdkConstant(SdkConstantType.FEATURE) - public static final String FEATURE_INCREMENTAL_DELIVERY_VERSION = - "android.software.incremental_delivery_version"; + public static final String FEATURE_INCREMENTAL_DELIVERY = + "android.software.incremental_delivery"; /** * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java index 2d381eb85e90..de48ed75746d 100644 --- a/core/java/android/content/res/ApkAssets.java +++ b/core/java/android/content/res/ApkAssets.java @@ -22,6 +22,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.om.OverlayableInfo; import android.content.res.loader.AssetsProvider; import android.content.res.loader.ResourcesProvider; +import android.text.TextUtils; import com.android.internal.annotations.GuardedBy; @@ -344,7 +345,14 @@ public final class ApkAssets { @UnsupportedAppUsage public @NonNull String getAssetPath() { synchronized (this) { - return nativeGetAssetPath(mNativePtr); + return TextUtils.emptyIfNull(nativeGetAssetPath(mNativePtr)); + } + } + + /** @hide */ + public @NonNull String getDebugName() { + synchronized (this) { + return nativeGetDebugName(mNativePtr); } } @@ -422,7 +430,7 @@ public final class ApkAssets { @Override public String toString() { - return "ApkAssets{path=" + getAssetPath() + "}"; + return "ApkAssets{path=" + getDebugName() + "}"; } /** @@ -450,6 +458,7 @@ public final class ApkAssets { @NonNull FileDescriptor fd, @NonNull String friendlyName, long offset, long length, @PropertyFlags int flags, @Nullable AssetsProvider asset) throws IOException; private static native @NonNull String nativeGetAssetPath(long ptr); + private static native @NonNull String nativeGetDebugName(long ptr); private static native long nativeGetStringBlock(long ptr); private static native boolean nativeIsUpToDate(long ptr); private static native long nativeOpenXml(long ptr, @NonNull String fileName) throws IOException; diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java index e247df320115..aafa7d520632 100644 --- a/core/java/android/hardware/display/ColorDisplayManager.java +++ b/core/java/android/hardware/display/ColorDisplayManager.java @@ -537,6 +537,26 @@ public final class ColorDisplayManager { } /** + * Returns the minimum allowed brightness reduction strength in percentage when activated. + * + * @hide + */ + public static int getMinimumReduceBrightColorsStrength(Context context) { + return context.getResources() + .getInteger(R.integer.config_reduceBrightColorsStrengthMin); + } + + /** + * Returns the maximum allowed brightness reduction strength in percentage when activated. + * + * @hide + */ + public static int getMaximumReduceBrightColorsStrength(Context context) { + return context.getResources() + .getInteger(R.integer.config_reduceBrightColorsStrengthMax); + } + + /** * Check if the color transforms are color accelerated. Some transforms are experimental only * on non-accelerated platforms due to the performance implications. * diff --git a/core/java/android/hardware/display/DeviceProductInfo.java b/core/java/android/hardware/display/DeviceProductInfo.java index 41126b70c89f..9457d8f1aac4 100644 --- a/core/java/android/hardware/display/DeviceProductInfo.java +++ b/core/java/android/hardware/display/DeviceProductInfo.java @@ -16,40 +16,69 @@ package android.hardware.display; +import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; -import java.util.Arrays; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** * Product-specific information about the display or the directly connected device on the * display chain. For example, if the display is transitively connected, this field may contain * product information about the intermediate device. - * @hide */ public final class DeviceProductInfo implements Parcelable { + /** @hide */ + @IntDef(prefix = {"CONNECTION_TO_SINK_"}, value = { + CONNECTION_TO_SINK_UNKNOWN, + CONNECTION_TO_SINK_BUILT_IN, + CONNECTION_TO_SINK_DIRECT, + CONNECTION_TO_SINK_TRANSITIVE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ConnectionToSinkType { } + + /** The device connection to the display sink is unknown. */ + public static final int CONNECTION_TO_SINK_UNKNOWN = + IDeviceProductInfoConstants.CONNECTION_TO_SINK_UNKNOWN; + + /** The display sink is built-in to the device */ + public static final int CONNECTION_TO_SINK_BUILT_IN = + IDeviceProductInfoConstants.CONNECTION_TO_SINK_BUILT_IN; + + /** The device is directly connected to the display sink. */ + public static final int CONNECTION_TO_SINK_DIRECT = + IDeviceProductInfoConstants.CONNECTION_TO_SINK_DIRECT; + + /** The device is transitively connected to the display sink. */ + public static final int CONNECTION_TO_SINK_TRANSITIVE = + IDeviceProductInfoConstants.CONNECTION_TO_SINK_TRANSITIVE; + private final String mName; private final String mManufacturerPnpId; private final String mProductId; private final Integer mModelYear; private final ManufactureDate mManufactureDate; - private final int[] mRelativeAddress; + private final @ConnectionToSinkType int mConnectionToSinkType; + /** @hide */ public DeviceProductInfo( String name, String manufacturerPnpId, String productId, Integer modelYear, ManufactureDate manufactureDate, - int[] relativeAddress) { + int connectionToSinkType) { this.mName = name; this.mManufacturerPnpId = manufacturerPnpId; this.mProductId = productId; this.mModelYear = modelYear; this.mManufactureDate = manufactureDate; - this.mRelativeAddress = relativeAddress; + this.mConnectionToSinkType = connectionToSinkType; } private DeviceProductInfo(Parcel in) { @@ -58,12 +87,13 @@ public final class DeviceProductInfo implements Parcelable { mProductId = (String) in.readValue(null); mModelYear = (Integer) in.readValue(null); mManufactureDate = (ManufactureDate) in.readValue(null); - mRelativeAddress = in.createIntArray(); + mConnectionToSinkType = in.readInt(); } /** * @return Display name. */ + @Nullable public String getName() { return mName; } @@ -71,6 +101,7 @@ public final class DeviceProductInfo implements Parcelable { /** * @return Manufacturer Plug and Play ID. */ + @NonNull public String getManufacturerPnpId() { return mManufacturerPnpId; } @@ -78,32 +109,58 @@ public final class DeviceProductInfo implements Parcelable { /** * @return Manufacturer product ID. */ + @NonNull public String getProductId() { return mProductId; } /** - * @return Model year of the device. Typically exactly one of model year or - * manufacture date will be present. + * @return Model year of the device. Return -1 if not available. Typically, + * one of model year or manufacture year is available. */ - public Integer getModelYear() { - return mModelYear; + public int getModelYear() { + return mModelYear != null ? mModelYear : -1; + } + + /** + * @return The year of manufacture, or -1 it is not available. Typically, + * one of model year or manufacture year is available. + */ + public int getManufactureYear() { + if (mManufactureDate == null) { + return -1; + } + return mManufactureDate.mYear != null ? mManufactureDate.mYear : -1; + } + + /** + * @return The week of manufacture, or -1 it is not available. Typically, + * not present if model year is available. + */ + public int getManufactureWeek() { + if (mManufactureDate == null) { + return -1; + } + return mManufactureDate.mWeek != null ? mManufactureDate.mWeek : -1; } /** * @return Manufacture date. Typically exactly one of model year or manufacture * date will be present. + * + * @hide */ public ManufactureDate getManufactureDate() { return mManufactureDate; } /** - * @return Relative address in the display network. For example, for HDMI connected devices this - * can be its physical address. Each component of the address is in the range [0, 255]. + * @return How the current device is connected to the display sink. For example, the display + * can be connected immediately to the device or there can be a receiver in between. */ - public int[] getRelativeAddress() { - return mRelativeAddress; + @ConnectionToSinkType + public int getConnectionToSinkType() { + return mConnectionToSinkType; } @Override @@ -119,8 +176,8 @@ public final class DeviceProductInfo implements Parcelable { + mModelYear + ", manufactureDate=" + mManufactureDate - + ", relativeAddress=" - + Arrays.toString(mRelativeAddress) + + ", connectionToSinkType=" + + mConnectionToSinkType + '}'; } @@ -134,16 +191,16 @@ public final class DeviceProductInfo implements Parcelable { && Objects.equals(mProductId, that.mProductId) && Objects.equals(mModelYear, that.mModelYear) && Objects.equals(mManufactureDate, that.mManufactureDate) - && Arrays.equals(mRelativeAddress, that.mRelativeAddress); + && mConnectionToSinkType == that.mConnectionToSinkType; } @Override public int hashCode() { return Objects.hash(mName, mManufacturerPnpId, mProductId, mModelYear, mManufactureDate, - Arrays.hashCode(mRelativeAddress)); + mConnectionToSinkType); } - public static final Creator<DeviceProductInfo> CREATOR = + @NonNull public static final Creator<DeviceProductInfo> CREATOR = new Creator<DeviceProductInfo>() { @Override public DeviceProductInfo createFromParcel(Parcel in) { @@ -162,13 +219,13 @@ public final class DeviceProductInfo implements Parcelable { } @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString(mName); dest.writeString(mManufacturerPnpId); dest.writeValue(mProductId); dest.writeValue(mModelYear); dest.writeValue(mManufactureDate); - dest.writeIntArray(mRelativeAddress); + dest.writeInt(mConnectionToSinkType); } /** diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 0baf11e850c7..dc3b88a7c3be 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -19,7 +19,7 @@ package android.net; import android.net.DataUsageRequest; import android.net.INetworkStatsSession; import android.net.Network; -import android.net.NetworkState; +import android.net.NetworkStateSnapshot; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; @@ -68,7 +68,7 @@ interface INetworkStatsService { /** Force update of ifaces. */ void forceUpdateIfaces( in Network[] defaultNetworks, - in NetworkState[] networkStates, + in NetworkStateSnapshot[] snapshots, in String activeIface, in UnderlyingNetworkInfo[] underlyingNetworkInfos); /** Force update of statistics. */ diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index e89451e4f4ef..8f1e2defd215 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -146,6 +146,25 @@ public final class IpSecAlgorithm implements Parcelable { public static final String AUTH_AES_XCBC = "xcbc(aes)"; /** + * AES-CMAC Authentication/Integrity Algorithm. + * + * <p>Keys for this algorithm must be 128 bits in length. + * + * <p>The only valid truncation length is 96 bits. + * + * <p>This algorithm may be available on the device. Caller MUST check if it is supported before + * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is + * included in the returned algorithm set. The returned algorithm set will not change unless the + * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is + * requested on an unsupported device. + * + * <p>@see {@link #getSupportedAlgorithms()} + */ + // This algorithm may be available on devices released before Android 12, and is guaranteed + // to be available on devices first shipped with Android 12 or later. + public static final String AUTH_AES_CMAC = "cmac(aes)"; + + /** * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm. * * <p>Valid lengths for keying material are {160, 224, 288}. @@ -191,6 +210,7 @@ public final class IpSecAlgorithm implements Parcelable { AUTH_HMAC_SHA384, AUTH_HMAC_SHA512, AUTH_AES_XCBC, + AUTH_AES_CMAC, AUTH_CRYPT_AES_GCM, AUTH_CRYPT_CHACHA20_POLY1305 }) @@ -215,6 +235,7 @@ public final class IpSecAlgorithm implements Parcelable { // STOPSHIP: b/170424293 Use Build.VERSION_CODES.S when it is defined ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.R + 1); ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.R + 1); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.R + 1); ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.R + 1); } @@ -383,6 +404,10 @@ public final class IpSecAlgorithm implements Parcelable { isValidLen = keyLen == 128; isValidTruncLen = truncLen == 96; break; + case AUTH_AES_CMAC: + isValidLen = keyLen == 128; + isValidTruncLen = truncLen == 96; + break; case AUTH_CRYPT_AES_GCM: // The keying material for GCM is a key plus a 32-bit salt isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32; @@ -416,6 +441,7 @@ public final class IpSecAlgorithm implements Parcelable { case AUTH_HMAC_SHA384: case AUTH_HMAC_SHA512: case AUTH_AES_XCBC: + case AUTH_AES_CMAC: return true; default: return false; diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 303a40755d4e..a5ece7b713c7 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -18,7 +18,6 @@ package android.net; import static android.net.ConnectivityManager.TYPE_WIFI; -import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.wifi.WifiInfo; @@ -180,29 +179,42 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { } /** - * Build a {@link NetworkIdentity} from the given {@link NetworkState} and {@code subType}, - * assuming that any mobile networks are using the current IMSI. The subType if applicable, - * should be set as one of the TelephonyManager.NETWORK_TYPE_* constants, or - * {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not. + * Build a {@link NetworkIdentity} from the given {@link NetworkState} and + * {@code subType}, assuming that any mobile networks are using the current IMSI. + * The subType if applicable, should be set as one of the TelephonyManager.NETWORK_TYPE_* + * constants, or {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not. */ - public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state, - boolean defaultNetwork, @NetworkType int subType) { - final int legacyType = state.legacyNetworkType; + // TODO: Delete this function after NetworkPolicyManagerService finishes the migration. + public static NetworkIdentity buildNetworkIdentity(Context context, + NetworkState state, boolean defaultNetwork, @NetworkType int subType) { + final NetworkStateSnapshot snapshot = new NetworkStateSnapshot(state.network, + state.networkCapabilities, state.linkProperties, state.subscriberId, + state.legacyNetworkType); + return buildNetworkIdentity(context, snapshot, defaultNetwork, subType); + } - String subscriberId = null; + /** + * Build a {@link NetworkIdentity} from the given {@link NetworkStateSnapshot} and + * {@code subType}, assuming that any mobile networks are using the current IMSI. + * The subType if applicable, should be set as one of the TelephonyManager.NETWORK_TYPE_* + * constants, or {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not. + */ + public static NetworkIdentity buildNetworkIdentity(Context context, + NetworkStateSnapshot snapshot, boolean defaultNetwork, @NetworkType int subType) { + final int legacyType = snapshot.legacyType; + + final String subscriberId = snapshot.subscriberId; String networkId = null; - boolean roaming = !state.networkCapabilities.hasCapability( + boolean roaming = !snapshot.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); - boolean metered = !state.networkCapabilities.hasCapability( + boolean metered = !snapshot.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - subscriberId = state.subscriberId; - - final int oemManaged = getOemBitfield(state.networkCapabilities); + final int oemManaged = getOemBitfield(snapshot.networkCapabilities); if (legacyType == TYPE_WIFI) { - if (state.networkCapabilities.getSsid() != null) { - networkId = state.networkCapabilities.getSsid(); + if (snapshot.networkCapabilities.getSsid() != null) { + networkId = snapshot.networkCapabilities.getSsid(); if (networkId == null) { // TODO: Figure out if this code path never runs. If so, remove them. final WifiManager wifi = (WifiManager) context.getSystemService( diff --git a/core/java/android/net/NetworkStateSnapshot.java b/core/java/android/net/NetworkStateSnapshot.java index 881b373fa241..b3d8d4e614da 100644 --- a/core/java/android/net/NetworkStateSnapshot.java +++ b/core/java/android/net/NetworkStateSnapshot.java @@ -16,8 +16,11 @@ package android.net; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; + import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -28,31 +31,49 @@ import java.util.Objects; * * @hide */ +@SystemApi(client = MODULE_LIBRARIES) public final class NetworkStateSnapshot implements Parcelable { + /** The network associated with this snapshot. */ @NonNull - public final LinkProperties linkProperties; + public final Network network; + + /** The {@link NetworkCapabilities} of the network associated with this snapshot. */ @NonNull public final NetworkCapabilities networkCapabilities; + + /** The {@link LinkProperties} of the network associated with this snapshot. */ @NonNull - public final Network network; + public final LinkProperties linkProperties; + + /** + * The Subscriber Id of the network associated with this snapshot. See + * {@link android.telephony.TelephonyManager#getSubscriberId()}. + */ @Nullable public final String subscriberId; + + /** + * The legacy type of the network associated with this snapshot. See + * {@code ConnectivityManager#TYPE_*}. + */ public final int legacyType; - public NetworkStateSnapshot(@NonNull LinkProperties linkProperties, - @NonNull NetworkCapabilities networkCapabilities, @NonNull Network network, + public NetworkStateSnapshot(@NonNull Network network, + @NonNull NetworkCapabilities networkCapabilities, + @NonNull LinkProperties linkProperties, @Nullable String subscriberId, int legacyType) { - this.linkProperties = Objects.requireNonNull(linkProperties); - this.networkCapabilities = Objects.requireNonNull(networkCapabilities); this.network = Objects.requireNonNull(network); + this.networkCapabilities = Objects.requireNonNull(networkCapabilities); + this.linkProperties = Objects.requireNonNull(linkProperties); this.subscriberId = subscriberId; this.legacyType = legacyType; } + /** @hide */ public NetworkStateSnapshot(@NonNull Parcel in) { - linkProperties = in.readParcelable(null); - networkCapabilities = in.readParcelable(null); network = in.readParcelable(null); + networkCapabilities = in.readParcelable(null); + linkProperties = in.readParcelable(null); subscriberId = in.readString(); legacyType = in.readInt(); } @@ -64,9 +85,9 @@ public final class NetworkStateSnapshot implements Parcelable { @Override public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeParcelable(linkProperties, flags); - out.writeParcelable(networkCapabilities, flags); out.writeParcelable(network, flags); + out.writeParcelable(networkCapabilities, flags); + out.writeParcelable(linkProperties, flags); out.writeString(subscriberId); out.writeInt(legacyType); } @@ -93,14 +114,14 @@ public final class NetworkStateSnapshot implements Parcelable { if (!(o instanceof NetworkStateSnapshot)) return false; NetworkStateSnapshot that = (NetworkStateSnapshot) o; return legacyType == that.legacyType - && Objects.equals(linkProperties, that.linkProperties) - && Objects.equals(networkCapabilities, that.networkCapabilities) && Objects.equals(network, that.network) + && Objects.equals(networkCapabilities, that.networkCapabilities) + && Objects.equals(linkProperties, that.linkProperties) && Objects.equals(subscriberId, that.subscriberId); } @Override public int hashCode() { - return Objects.hash(linkProperties, networkCapabilities, network, subscriberId, legacyType); + return Objects.hash(network, networkCapabilities, linkProperties, subscriberId, legacyType); } } diff --git a/packages/Connectivity/framework/src/android/net/PacProxySelector.java b/core/java/android/net/PacProxySelector.java index 326943a27d4e..326943a27d4e 100644 --- a/packages/Connectivity/framework/src/android/net/PacProxySelector.java +++ b/core/java/android/net/PacProxySelector.java diff --git a/packages/Connectivity/framework/src/android/net/Proxy.java b/core/java/android/net/Proxy.java index 77c8a4f4579b..77c8a4f4579b 100644 --- a/packages/Connectivity/framework/src/android/net/Proxy.java +++ b/core/java/android/net/Proxy.java diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java index f90fbaf1e0fb..fa3ff8a26862 100644 --- a/core/java/android/net/VpnService.java +++ b/core/java/android/net/VpnService.java @@ -41,6 +41,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import com.android.internal.net.NetworkUtilsInternal; import com.android.internal.net.VpnConfig; import java.net.DatagramSocket; @@ -254,7 +255,7 @@ public class VpnService extends Service { * @return {@code true} on success. */ public boolean protect(int socket) { - return NetworkUtils.protectFromVpn(socket); + return NetworkUtilsInternal.protectFromVpn(socket); } /** diff --git a/packages/Connectivity/framework/src/android/net/util/SocketUtils.java b/core/java/android/net/util/SocketUtils.java index e64060f1b220..69edc757ce8a 100644 --- a/packages/Connectivity/framework/src/android/net/util/SocketUtils.java +++ b/core/java/android/net/util/SocketUtils.java @@ -22,12 +22,13 @@ import static android.system.OsConstants.SO_BINDTODEVICE; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.net.NetworkUtils; import android.system.ErrnoException; import android.system.NetlinkSocketAddress; import android.system.Os; import android.system.PacketSocketAddress; +import com.android.internal.net.NetworkUtilsInternal; + import libcore.io.IoBridge; import java.io.FileDescriptor; @@ -51,7 +52,7 @@ public final class SocketUtils { // of struct ifreq is a NULL-terminated interface name. // TODO: add a setsockoptString() Os.setsockoptIfreq(socket, SOL_SOCKET, SO_BINDTODEVICE, iface); - NetworkUtils.protectFromVpn(socket); + NetworkUtilsInternal.protectFromVpn(socket); } /** diff --git a/core/java/android/os/BatterySaverPolicyConfig.java b/core/java/android/os/BatterySaverPolicyConfig.java index 81c781bff06d..a999e658ce21 100644 --- a/core/java/android/os/BatterySaverPolicyConfig.java +++ b/core/java/android/os/BatterySaverPolicyConfig.java @@ -247,6 +247,7 @@ public final class BatterySaverPolicyConfig implements Parcelable { /** * Get the SoundTrigger mode while in Battery Saver. */ + @PowerManager.SoundTriggerPowerSaveMode public int getSoundTriggerMode() { return mSoundTriggerMode; } diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index 874add5cdbd8..91d6a9bf69cb 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -23,7 +23,6 @@ import android.net.ITetheringStatsProvider; import android.net.Network; import android.net.NetworkStats; import android.net.RouteInfo; -import android.net.UidRange; /** * @hide @@ -182,11 +181,6 @@ interface INetworkManagementService String[] listTetheredInterfaces(); /** - * Sets the list of DNS forwarders (in order of priority) - */ - void setDnsForwarders(in Network network, in String[] dns); - - /** * Returns the list of DNS forwarders (in order of priority) */ String[] getDnsForwarders(); @@ -300,8 +294,6 @@ interface INetworkManagementService void setFirewallUidRules(int chain, in int[] uids, in int[] rules); void setFirewallChainEnabled(int chain, boolean enable); - void addLegacyRouteForNetId(int netId, in RouteInfo routeInfo, int uid); - /** * Allow UID to call protect(). */ diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 617220e00f9d..85cef84d8d30 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -16564,30 +16564,6 @@ public final class Settings { /** * Performs a strict and comprehensive check of whether a calling package is allowed to - * change the state of network, as the condition differs for pre-M, M+, and - * privileged/preinstalled apps. The caller is expected to have either the - * CHANGE_NETWORK_STATE or the WRITE_SETTINGS permission declared. Either of these - * permissions allow changing network state; WRITE_SETTINGS is a runtime permission and - * can be revoked, but (except in M, excluding M MRs), CHANGE_NETWORK_STATE is a normal - * permission and cannot be revoked. See http://b/23597341 - * - * Note: if the check succeeds because the application holds WRITE_SETTINGS, the operation - * of this app will be updated to the current time. - * @hide - */ - public static boolean checkAndNoteChangeNetworkStateOperation(Context context, int uid, - String callingPackage, String callingAttributionTag, boolean throwException) { - if (context.checkCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE) - == PackageManager.PERMISSION_GRANTED) { - return true; - } - return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid, - callingPackage, callingAttributionTag, throwException, - AppOpsManager.OP_WRITE_SETTINGS, PM_CHANGE_NETWORK_STATE, true); - } - - /** - * Performs a strict and comprehensive check of whether a calling package is allowed to * draw on top of other apps, as the conditions differs for pre-M, M+, and * privileged/preinstalled apps. If the provided uid does not match the callingPackage, * a negative result will be returned. diff --git a/core/java/android/util/OWNERS b/core/java/android/util/OWNERS index 14aa38682d2b..5425c214de1f 100644 --- a/core/java/android/util/OWNERS +++ b/core/java/android/util/OWNERS @@ -2,5 +2,7 @@ per-file FeatureFlagUtils.java = sbasi@google.com per-file FeatureFlagUtils.java = tmfang@google.com per-file FeatureFlagUtils.java = asapperstein@google.com -per-file TypedValue.java = file:/core/java/android/content/res/OWNERS per-file AttributeSet.java = file:/core/java/android/content/res/OWNERS +per-file TypedValue.java = file:/core/java/android/content/res/OWNERS + +per-file PackageUtils.java = file:/core/java/android/content/pm/OWNERS diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java index 6718e93f908c..05c8617294da 100644 --- a/core/java/android/util/SparseArray.java +++ b/core/java/android/util/SparseArray.java @@ -510,10 +510,12 @@ public class SparseArray<E> implements Cloneable { } /** + * Compares the contents of this {@link SparseArray} to the specified {@link SparseArray}. + * * For backwards compatibility reasons, {@link Object#equals(Object)} cannot be implemented, * so this serves as a manually invoked alternative. */ - public boolean contentEquals(@Nullable SparseArray<E> other) { + public boolean contentEquals(@Nullable SparseArray<?> other) { if (other == null) { return false; } @@ -534,6 +536,9 @@ public class SparseArray<E> implements Cloneable { } /** + * Returns a hash code value for the contents of this {@link SparseArray}, combining the + * {@link Objects#hashCode(Object)} result of all its keys and values. + * * For backwards compatibility, {@link Object#hashCode()} cannot be implemented, so this serves * as a manually invoked alternative. */ diff --git a/core/java/android/util/apk/OWNERS b/core/java/android/util/apk/OWNERS new file mode 100644 index 000000000000..52c95501e541 --- /dev/null +++ b/core/java/android/util/apk/OWNERS @@ -0,0 +1 @@ +include /core/java/android/content/pm/OWNERS diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index 9473845b15e6..0499f39f2fe4 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -86,12 +86,19 @@ public final class AccessibilityInteractionController { // accessibility from hanging private static final long REQUEST_PREPARER_TIMEOUT_MS = 500; + // Callbacks should have the same configuration of the flags below to allow satisfying a pending + // node request on prefetch + private static final int FLAGS_AFFECTING_REPORTED_DATA = + AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS + | AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS; + private final ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList = new ArrayList<AccessibilityNodeInfo>(); private final Object mLock = new Object(); - private final PrivateHandler mHandler; + @VisibleForTesting + public final PrivateHandler mHandler; private final ViewRootImpl mViewRootImpl; @@ -114,6 +121,9 @@ public final class AccessibilityInteractionController { private AddNodeInfosForViewId mAddNodeInfosForViewId; @GuardedBy("mLock") + private ArrayList<Message> mPendingFindNodeByIdMessages; + + @GuardedBy("mLock") private int mNumActiveRequestPreparers; @GuardedBy("mLock") private List<MessageHolder> mMessagesWaitingForRequestPreparer; @@ -128,6 +138,7 @@ public final class AccessibilityInteractionController { mViewRootImpl = viewRootImpl; mPrefetcher = new AccessibilityNodePrefetcher(); mA11yManager = mViewRootImpl.mContext.getSystemService(AccessibilityManager.class); + mPendingFindNodeByIdMessages = new ArrayList<>(); } private void scheduleMessage(Message message, int interrogatingPid, long interrogatingTid, @@ -177,6 +188,9 @@ public final class AccessibilityInteractionController { args.arg4 = arguments; message.obj = args; + synchronized (mLock) { + mPendingFindNodeByIdMessages.add(message); + } scheduleMessage(message, interrogatingPid, interrogatingTid, CONSIDER_REQUEST_PREPARERS); } @@ -315,6 +329,9 @@ public final class AccessibilityInteractionController { } private void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) { + synchronized (mLock) { + mPendingFindNodeByIdMessages.remove(message); + } final int flags = message.arg1; SomeArgs args = (SomeArgs) message.obj; @@ -329,22 +346,58 @@ public final class AccessibilityInteractionController { args.recycle(); - List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList; - infos.clear(); + View rootView = null; + AccessibilityNodeInfo rootNode = null; try { if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) { return; } mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags; - final View root = findViewByAccessibilityId(accessibilityViewId); - if (root != null && isShown(root)) { - mPrefetcher.prefetchAccessibilityNodeInfos( - root, virtualDescendantId, flags, infos, arguments); + rootView = findViewByAccessibilityId(accessibilityViewId); + if (rootView != null && isShown(rootView)) { + rootNode = populateAccessibilityNodeInfoForView( + rootView, arguments, virtualDescendantId); } } finally { - updateInfosForViewportAndReturnFindNodeResult( - infos, callback, interactionId, spec, interactiveRegion); + updateInfoForViewportAndReturnFindNodeResult( + rootNode == null ? null : AccessibilityNodeInfo.obtain(rootNode), + callback, interactionId, spec, interactiveRegion); + } + ArrayList<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList; + infos.clear(); + mPrefetcher.prefetchAccessibilityNodeInfos( + rootView, rootNode == null ? null : AccessibilityNodeInfo.obtain(rootNode), + virtualDescendantId, flags, infos); + mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; + updateInfosForViewPort(infos, spec, interactiveRegion); + returnPrefetchResult(interactionId, infos, callback); + returnPendingFindAccessibilityNodeInfosInPrefetch(rootNode, infos, flags); + } + + private AccessibilityNodeInfo populateAccessibilityNodeInfoForView( + View view, Bundle arguments, int virtualViewId) { + AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider(); + // Determine if we'll be populating extra data + final String extraDataRequested = (arguments == null) ? null + : arguments.getString(EXTRA_DATA_REQUESTED_KEY); + AccessibilityNodeInfo root = null; + if (provider == null) { + root = view.createAccessibilityNodeInfo(); + if (root != null) { + if (extraDataRequested != null) { + view.addExtraDataToAccessibilityNodeInfo(root, extraDataRequested, arguments); + } + } + } else { + root = provider.createAccessibilityNodeInfo(virtualViewId); + if (root != null) { + if (extraDataRequested != null) { + provider.addExtraDataToAccessibilityNodeInfo( + virtualViewId, root, extraDataRequested, arguments); + } + } } + return root; } public void findAccessibilityNodeInfosByViewIdClientThread(long accessibilityNodeId, @@ -402,6 +455,7 @@ public final class AccessibilityInteractionController { mAddNodeInfosForViewId.reset(); } } finally { + mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; updateInfosForViewportAndReturnFindNodeResult( infos, callback, interactionId, spec, interactiveRegion); } @@ -484,6 +538,7 @@ public final class AccessibilityInteractionController { } } } finally { + mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; updateInfosForViewportAndReturnFindNodeResult( infos, callback, interactionId, spec, interactiveRegion); } @@ -575,6 +630,7 @@ public final class AccessibilityInteractionController { } } } finally { + mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; updateInfoForViewportAndReturnFindNodeResult( focused, callback, interactionId, spec, interactiveRegion); } @@ -629,6 +685,7 @@ public final class AccessibilityInteractionController { } } } finally { + mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; updateInfoForViewportAndReturnFindNodeResult( next, callback, interactionId, spec, interactiveRegion); } @@ -785,33 +842,6 @@ public final class AccessibilityInteractionController { } } - private void applyAppScaleAndMagnificationSpecIfNeeded(List<AccessibilityNodeInfo> infos, - MagnificationSpec spec) { - if (infos == null) { - return; - } - final float applicationScale = mViewRootImpl.mAttachInfo.mApplicationScale; - if (shouldApplyAppScaleAndMagnificationSpec(applicationScale, spec)) { - final int infoCount = infos.size(); - for (int i = 0; i < infoCount; i++) { - AccessibilityNodeInfo info = infos.get(i); - applyAppScaleAndMagnificationSpecIfNeeded(info, spec); - } - } - } - - private void adjustIsVisibleToUserIfNeeded(List<AccessibilityNodeInfo> infos, - Region interactiveRegion) { - if (interactiveRegion == null || infos == null) { - return; - } - final int infoCount = infos.size(); - for (int i = 0; i < infoCount; i++) { - AccessibilityNodeInfo info = infos.get(i); - adjustIsVisibleToUserIfNeeded(info, interactiveRegion); - } - } - private void adjustIsVisibleToUserIfNeeded(AccessibilityNodeInfo info, Region interactiveRegion) { if (interactiveRegion == null || info == null) { @@ -832,17 +862,6 @@ public final class AccessibilityInteractionController { return false; } - private void adjustBoundsInScreenIfNeeded(List<AccessibilityNodeInfo> infos) { - if (infos == null || shouldBypassAdjustBoundsInScreen()) { - return; - } - final int infoCount = infos.size(); - for (int i = 0; i < infoCount; i++) { - final AccessibilityNodeInfo info = infos.get(i); - adjustBoundsInScreenIfNeeded(info); - } - } - private void adjustBoundsInScreenIfNeeded(AccessibilityNodeInfo info) { if (info == null || shouldBypassAdjustBoundsInScreen()) { return; @@ -890,17 +909,6 @@ public final class AccessibilityInteractionController { return screenMatrix == null || screenMatrix.isIdentity(); } - private void associateLeashedParentIfNeeded(List<AccessibilityNodeInfo> infos) { - if (infos == null || shouldBypassAssociateLeashedParent()) { - return; - } - final int infoCount = infos.size(); - for (int i = 0; i < infoCount; i++) { - final AccessibilityNodeInfo info = infos.get(i); - associateLeashedParentIfNeeded(info); - } - } - private void associateLeashedParentIfNeeded(AccessibilityNodeInfo info) { if (info == null || shouldBypassAssociateLeashedParent()) { return; @@ -974,18 +982,46 @@ public final class AccessibilityInteractionController { return (appScale != 1.0f || (spec != null && !spec.isNop())); } + private void updateInfosForViewPort(List<AccessibilityNodeInfo> infos, MagnificationSpec spec, + Region interactiveRegion) { + for (int i = 0; i < infos.size(); i++) { + updateInfoForViewPort(infos.get(i), spec, interactiveRegion); + } + } + + private void updateInfoForViewPort(AccessibilityNodeInfo info, MagnificationSpec spec, + Region interactiveRegion) { + associateLeashedParentIfNeeded(info); + applyScreenMatrixIfNeeded(info); + adjustBoundsInScreenIfNeeded(info); + // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node, + // then impact the visibility result, we need to adjust visibility before apply scale. + adjustIsVisibleToUserIfNeeded(info, interactiveRegion); + applyAppScaleAndMagnificationSpecIfNeeded(info, spec); + } + private void updateInfosForViewportAndReturnFindNodeResult(List<AccessibilityNodeInfo> infos, IAccessibilityInteractionConnectionCallback callback, int interactionId, MagnificationSpec spec, Region interactiveRegion) { + if (infos != null) { + updateInfosForViewPort(infos, spec, interactiveRegion); + } + returnFindNodesResult(infos, callback, interactionId); + } + + private void returnFindNodeResult(AccessibilityNodeInfo info, + IAccessibilityInteractionConnectionCallback callback, + int interactionId) { + try { + callback.setFindAccessibilityNodeInfoResult(info, interactionId); + } catch (RemoteException re) { + /* ignore - the other side will time out */ + } + } + + private void returnFindNodesResult(List<AccessibilityNodeInfo> infos, + IAccessibilityInteractionConnectionCallback callback, int interactionId) { try { - mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; - associateLeashedParentIfNeeded(infos); - applyScreenMatrixIfNeeded(infos); - adjustBoundsInScreenIfNeeded(infos); - // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node, - // then impact the visibility result, we need to adjust visibility before apply scale. - adjustIsVisibleToUserIfNeeded(infos, interactiveRegion); - applyAppScaleAndMagnificationSpecIfNeeded(infos, spec); callback.setFindAccessibilityNodeInfosResult(infos, interactionId); if (infos != null) { infos.clear(); @@ -995,22 +1031,80 @@ public final class AccessibilityInteractionController { } } + private void returnPendingFindAccessibilityNodeInfosInPrefetch(AccessibilityNodeInfo rootNode, + List<AccessibilityNodeInfo> infos, int flags) { + + AccessibilityNodeInfo satisfiedPendingRequestPrefetchedNode = null; + IAccessibilityInteractionConnectionCallback satisfiedPendingRequestCallback = null; + int satisfiedPendingRequestInteractionId = AccessibilityInteractionClient.NO_ID; + + synchronized (mLock) { + for (int i = 0; i < mPendingFindNodeByIdMessages.size(); i++) { + final Message pendingMessage = mPendingFindNodeByIdMessages.get(i); + final int pendingFlags = pendingMessage.arg1; + if ((pendingFlags & FLAGS_AFFECTING_REPORTED_DATA) + != (flags & FLAGS_AFFECTING_REPORTED_DATA)) { + continue; + } + SomeArgs args = (SomeArgs) pendingMessage.obj; + final int accessibilityViewId = args.argi1; + final int virtualDescendantId = args.argi2; + + satisfiedPendingRequestPrefetchedNode = nodeWithIdFromList(rootNode, + infos, AccessibilityNodeInfo.makeNodeId( + accessibilityViewId, virtualDescendantId)); + + if (satisfiedPendingRequestPrefetchedNode != null) { + satisfiedPendingRequestCallback = + (IAccessibilityInteractionConnectionCallback) args.arg1; + satisfiedPendingRequestInteractionId = args.argi3; + mHandler.removeMessages( + PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID, + pendingMessage.obj); + args.recycle(); + break; + } + } + mPendingFindNodeByIdMessages.clear(); + } + + if (satisfiedPendingRequestPrefetchedNode != null) { + returnFindNodeResult( + AccessibilityNodeInfo.obtain(satisfiedPendingRequestPrefetchedNode), + satisfiedPendingRequestCallback, satisfiedPendingRequestInteractionId); + } + } + + private AccessibilityNodeInfo nodeWithIdFromList(AccessibilityNodeInfo rootNode, + List<AccessibilityNodeInfo> infos, long nodeId) { + if (rootNode != null && rootNode.getSourceNodeId() == nodeId) { + return rootNode; + } + for (int j = 0; j < infos.size(); j++) { + AccessibilityNodeInfo info = infos.get(j); + if (info.getSourceNodeId() == nodeId) { + return info; + } + } + return null; + } + + private void returnPrefetchResult(int interactionId, List<AccessibilityNodeInfo> infos, + IAccessibilityInteractionConnectionCallback callback) { + if (infos.size() > 0) { + try { + callback.setPrefetchAccessibilityNodeInfoResult(infos, interactionId); + } catch (RemoteException re) { + /* ignore - other side isn't too bothered if this doesn't arrive */ + } + } + } + private void updateInfoForViewportAndReturnFindNodeResult(AccessibilityNodeInfo info, IAccessibilityInteractionConnectionCallback callback, int interactionId, MagnificationSpec spec, Region interactiveRegion) { - try { - mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; - associateLeashedParentIfNeeded(info); - applyScreenMatrixIfNeeded(info); - adjustBoundsInScreenIfNeeded(info); - // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node, - // then impact the visibility result, we need to adjust visibility before apply scale. - adjustIsVisibleToUserIfNeeded(info, interactiveRegion); - applyAppScaleAndMagnificationSpecIfNeeded(info, spec); - callback.setFindAccessibilityNodeInfoResult(info, interactionId); - } catch (RemoteException re) { - /* ignore - the other side will time out */ - } + updateInfoForViewPort(info, spec, interactiveRegion); + returnFindNodeResult(info, callback, interactionId); } private boolean handleClickableSpanActionUiThread( @@ -1053,56 +1147,45 @@ public final class AccessibilityInteractionController { private final ArrayList<View> mTempViewList = new ArrayList<View>(); - public void prefetchAccessibilityNodeInfos(View view, int virtualViewId, int fetchFlags, - List<AccessibilityNodeInfo> outInfos, Bundle arguments) { + public void prefetchAccessibilityNodeInfos(View view, AccessibilityNodeInfo root, + int virtualViewId, int fetchFlags, List<AccessibilityNodeInfo> outInfos) { + if (root == null) { + return; + } AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider(); - // Determine if we'll be populating extra data - final String extraDataRequested = (arguments == null) ? null - : arguments.getString(EXTRA_DATA_REQUESTED_KEY); if (provider == null) { - AccessibilityNodeInfo root = view.createAccessibilityNodeInfo(); - if (root != null) { - if (extraDataRequested != null) { - view.addExtraDataToAccessibilityNodeInfo( - root, extraDataRequested, arguments); - } - outInfos.add(root); - if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) { - prefetchPredecessorsOfRealNode(view, outInfos); - } - if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) { - prefetchSiblingsOfRealNode(view, outInfos); - } - if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) { - prefetchDescendantsOfRealNode(view, outInfos); - } + if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) { + prefetchPredecessorsOfRealNode(view, outInfos); + } + if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) { + prefetchSiblingsOfRealNode(view, outInfos); + } + if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) { + prefetchDescendantsOfRealNode(view, outInfos); } } else { - final AccessibilityNodeInfo root = - provider.createAccessibilityNodeInfo(virtualViewId); - if (root != null) { - if (extraDataRequested != null) { - provider.addExtraDataToAccessibilityNodeInfo( - virtualViewId, root, extraDataRequested, arguments); - } - outInfos.add(root); - if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) { - prefetchPredecessorsOfVirtualNode(root, view, provider, outInfos); - } - if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) { - prefetchSiblingsOfVirtualNode(root, view, provider, outInfos); - } - if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) { - prefetchDescendantsOfVirtualNode(root, provider, outInfos); - } + if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) { + prefetchPredecessorsOfVirtualNode(root, view, provider, outInfos); + } + if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) { + prefetchSiblingsOfVirtualNode(root, view, provider, outInfos); + } + if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) { + prefetchDescendantsOfVirtualNode(root, provider, outInfos); } } if (ENFORCE_NODE_TREE_CONSISTENT) { - enforceNodeTreeConsistent(outInfos); + enforceNodeTreeConsistent(root, outInfos); } } - private void enforceNodeTreeConsistent(List<AccessibilityNodeInfo> nodes) { + private boolean shouldStopPrefetching(List prefetchededInfos) { + return mHandler.hasUserInteractiveMessagesWaiting() + || prefetchededInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE; + } + + private void enforceNodeTreeConsistent( + AccessibilityNodeInfo root, List<AccessibilityNodeInfo> nodes) { LongSparseArray<AccessibilityNodeInfo> nodeMap = new LongSparseArray<AccessibilityNodeInfo>(); final int nodeCount = nodes.size(); @@ -1113,7 +1196,6 @@ public final class AccessibilityInteractionController { // If the nodes are a tree it does not matter from // which node we start to search for the root. - AccessibilityNodeInfo root = nodeMap.valueAt(0); AccessibilityNodeInfo parent = root; while (parent != null) { root = parent; @@ -1180,9 +1262,11 @@ public final class AccessibilityInteractionController { private void prefetchPredecessorsOfRealNode(View view, List<AccessibilityNodeInfo> outInfos) { + if (shouldStopPrefetching(outInfos)) { + return; + } ViewParent parent = view.getParentForAccessibility(); - while (parent instanceof View - && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { + while (parent instanceof View && !shouldStopPrefetching(outInfos)) { View parentView = (View) parent; AccessibilityNodeInfo info = parentView.createAccessibilityNodeInfo(); if (info != null) { @@ -1194,6 +1278,9 @@ public final class AccessibilityInteractionController { private void prefetchSiblingsOfRealNode(View current, List<AccessibilityNodeInfo> outInfos) { + if (shouldStopPrefetching(outInfos)) { + return; + } ViewParent parent = current.getParentForAccessibility(); if (parent instanceof ViewGroup) { ViewGroup parentGroup = (ViewGroup) parent; @@ -1203,7 +1290,7 @@ public final class AccessibilityInteractionController { parentGroup.addChildrenForAccessibility(children); final int childCount = children.size(); for (int i = 0; i < childCount; i++) { - if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { + if (shouldStopPrefetching(outInfos)) { return; } View child = children.get(i); @@ -1231,7 +1318,7 @@ public final class AccessibilityInteractionController { private void prefetchDescendantsOfRealNode(View root, List<AccessibilityNodeInfo> outInfos) { - if (!(root instanceof ViewGroup)) { + if (shouldStopPrefetching(outInfos) || !(root instanceof ViewGroup)) { return; } HashMap<View, AccessibilityNodeInfo> addedChildren = @@ -1242,7 +1329,7 @@ public final class AccessibilityInteractionController { root.addChildrenForAccessibility(children); final int childCount = children.size(); for (int i = 0; i < childCount; i++) { - if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { + if (shouldStopPrefetching(outInfos)) { return; } View child = children.get(i); @@ -1267,7 +1354,7 @@ public final class AccessibilityInteractionController { } finally { children.clear(); } - if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { + if (!shouldStopPrefetching(outInfos)) { for (Map.Entry<View, AccessibilityNodeInfo> entry : addedChildren.entrySet()) { View addedChild = entry.getKey(); AccessibilityNodeInfo virtualRoot = entry.getValue(); @@ -1289,7 +1376,7 @@ public final class AccessibilityInteractionController { long parentNodeId = root.getParentNodeId(); int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(parentNodeId); while (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) { - if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { + if (shouldStopPrefetching(outInfos)) { return; } final int virtualDescendantId = @@ -1334,7 +1421,7 @@ public final class AccessibilityInteractionController { if (parent != null) { final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { - if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { + if (shouldStopPrefetching(outInfos)) { return; } final long childNodeId = parent.getChildId(i); @@ -1359,7 +1446,7 @@ public final class AccessibilityInteractionController { final int initialOutInfosSize = outInfos.size(); final int childCount = root.getChildCount(); for (int i = 0; i < childCount; i++) { - if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { + if (shouldStopPrefetching(outInfos)) { return; } final long childNodeId = root.getChildId(i); @@ -1369,7 +1456,7 @@ public final class AccessibilityInteractionController { outInfos.add(child); } } - if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) { + if (!shouldStopPrefetching(outInfos)) { final int addedChildCount = outInfos.size() - initialOutInfosSize; for (int i = 0; i < addedChildCount; i++) { AccessibilityNodeInfo child = outInfos.get(initialOutInfosSize + i); @@ -1478,6 +1565,10 @@ public final class AccessibilityInteractionController { boolean hasAccessibilityCallback(Message message) { return message.what < FIRST_NO_ACCESSIBILITY_CALLBACK_MSG ? true : false; } + + boolean hasUserInteractiveMessagesWaiting() { + return hasMessagesOrCallbacks(); + } } private final class AddNodeInfosForViewId implements Predicate<View> { diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 0ba1dfee16f3..8117c963b959 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -34,6 +34,7 @@ import android.graphics.ColorSpace; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; +import android.hardware.display.DeviceProductInfo; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerGlobal; import android.os.Build; @@ -1181,6 +1182,18 @@ public final class Display { } /** + * Returns the product-specific information about the display or the directly connected + * device on the display chain. + * For example, if the display is transitively connected, this field may contain product + * information about the intermediate device. + * Returns {@code null} if product information is not available. + */ + @Nullable + public DeviceProductInfo getDeviceProductInfo() { + return mDisplayInfo.deviceProductInfo; + } + + /** * Gets display metrics that describe the size and density of this display. * The size returned by this method does not necessarily represent the * actual raw size (native resolution) of the display. diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS index e66b17aa4426..cbb86de4785f 100644 --- a/core/java/android/view/OWNERS +++ b/core/java/android/view/OWNERS @@ -57,6 +57,7 @@ per-file ViewRootImpl.java = file:/graphics/java/android/graphics/OWNERS per-file ViewRootImpl.java = file:/services/core/java/com/android/server/input/OWNERS per-file ViewRootImpl.java = file:/services/core/java/com/android/server/wm/OWNERS per-file ViewRootImpl.java = file:/core/java/android/view/inputmethod/OWNERS +per-file AccessibilityInteractionController.java = file:/services/accessibility/OWNERS # WindowManager per-file DisplayCutout.aidl = file:/services/core/java/com/android/server/wm/OWNERS diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 2053826d91a9..1819da4a86a0 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -2782,6 +2782,15 @@ public interface WindowManager extends ViewManager { public boolean hasManualSurfaceInsets; /** + * Whether we should use global insets state when report insets to the window. When set to + * {@code true}, all the insets will be reported to the window regardless of the z-order. + * Otherwise, only the insets above the given window will be reported. + * + * @hide + */ + public boolean receiveInsetsIgnoringZOrder; + + /** * Whether the previous surface insets should be used vs. what is currently set. When set * to {@code true}, the view root will ignore surfaces insets in this object and use what * it currently has. @@ -3714,15 +3723,16 @@ public interface WindowManager extends ViewManager { out.writeInt(preferredDisplayModeId); out.writeInt(systemUiVisibility); out.writeInt(subtreeSystemUiVisibility); - out.writeInt(hasSystemUiListeners ? 1 : 0); + out.writeBoolean(hasSystemUiListeners); out.writeInt(inputFeatures); out.writeLong(userActivityTimeout); out.writeInt(surfaceInsets.left); out.writeInt(surfaceInsets.top); out.writeInt(surfaceInsets.right); out.writeInt(surfaceInsets.bottom); - out.writeInt(hasManualSurfaceInsets ? 1 : 0); - out.writeInt(preservePreviousSurfaceInsets ? 1 : 0); + out.writeBoolean(hasManualSurfaceInsets); + out.writeBoolean(receiveInsetsIgnoringZOrder); + out.writeBoolean(preservePreviousSurfaceInsets); out.writeLong(accessibilityIdOfAnchor); TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags); out.writeInt(mColorMode); @@ -3783,15 +3793,16 @@ public interface WindowManager extends ViewManager { preferredDisplayModeId = in.readInt(); systemUiVisibility = in.readInt(); subtreeSystemUiVisibility = in.readInt(); - hasSystemUiListeners = in.readInt() != 0; + hasSystemUiListeners = in.readBoolean(); inputFeatures = in.readInt(); userActivityTimeout = in.readLong(); surfaceInsets.left = in.readInt(); surfaceInsets.top = in.readInt(); surfaceInsets.right = in.readInt(); surfaceInsets.bottom = in.readInt(); - hasManualSurfaceInsets = in.readInt() != 0; - preservePreviousSurfaceInsets = in.readInt() != 0; + hasManualSurfaceInsets = in.readBoolean(); + receiveInsetsIgnoringZOrder = in.readBoolean(); + preservePreviousSurfaceInsets = in.readBoolean(); accessibilityIdOfAnchor = in.readLong(); accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); mColorMode = in.readInt(); @@ -4020,6 +4031,11 @@ public interface WindowManager extends ViewManager { changes |= SURFACE_INSETS_CHANGED; } + if (receiveInsetsIgnoringZOrder != o.receiveInsetsIgnoringZOrder) { + receiveInsetsIgnoringZOrder = o.receiveInsetsIgnoringZOrder; + changes |= SURFACE_INSETS_CHANGED; + } + if (preservePreviousSurfaceInsets != o.preservePreviousSurfaceInsets) { preservePreviousSurfaceInsets = o.preservePreviousSurfaceInsets; changes |= SURFACE_INSETS_CHANGED; @@ -4208,6 +4224,9 @@ public interface WindowManager extends ViewManager { sb.append(" (!preservePreviousSurfaceInsets)"); } } + if (receiveInsetsIgnoringZOrder) { + sb.append(" receive insets ignoring z-order"); + } if (mColorMode != COLOR_MODE_DEFAULT) { sb.append(" colorMode=").append(ActivityInfo.colorModeToString(mColorMode)); } diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java index f63749be6df2..9556c25575cd 100644 --- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java +++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java @@ -23,7 +23,9 @@ import android.compat.annotation.UnsupportedAppUsage; import android.os.Binder; import android.os.Build; import android.os.Bundle; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.Message; import android.os.Process; import android.os.RemoteException; @@ -113,6 +115,8 @@ public final class AccessibilityInteractionClient private final Object mInstanceLock = new Object(); + private Handler mMainHandler; + private volatile int mInteractionId = -1; private AccessibilityNodeInfo mFindAccessibilityNodeInfoResult; @@ -123,6 +127,11 @@ public final class AccessibilityInteractionClient private Message mSameThreadMessage; + private int mInteractionIdWaitingForPrefetchResult; + private int mConnectionIdWaitingForPrefetchResult; + private String[] mPackageNamesForNextPrefetchResult; + private Runnable mPrefetchResultRunnable; + /** * @return The client for the current thread. */ @@ -197,6 +206,9 @@ public final class AccessibilityInteractionClient private AccessibilityInteractionClient() { /* reducing constructor visibility */ + if (Looper.getMainLooper() != null) { + mMainHandler = new Handler(Looper.getMainLooper()); + } } /** @@ -451,16 +463,16 @@ public final class AccessibilityInteractionClient Binder.restoreCallingIdentity(identityToken); } if (packageNames != null) { - List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( - interactionId); - finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, - bypassCache, packageNames); - if (infos != null && !infos.isEmpty()) { - for (int i = 1; i < infos.size(); i++) { - infos.get(i).recycle(); - } - return infos.get(0); + AccessibilityNodeInfo info = + getFindAccessibilityNodeInfoResultAndClear(interactionId); + if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_MASK) != 0 + && info != null) { + setInteractionWaitingForPrefetchResult(interactionId, connectionId, + packageNames); } + finalizeAndCacheAccessibilityNodeInfo(info, connectionId, + bypassCache, packageNames); + return info; } } else { if (DEBUG) { @@ -474,6 +486,15 @@ public final class AccessibilityInteractionClient return null; } + private void setInteractionWaitingForPrefetchResult(int interactionId, int connectionId, + String[] packageNames) { + synchronized (mInstanceLock) { + mInteractionIdWaitingForPrefetchResult = interactionId; + mConnectionIdWaitingForPrefetchResult = connectionId; + mPackageNamesForNextPrefetchResult = packageNames; + } + } + private static String idToString(int accessibilityWindowId, long accessibilityNodeId) { return accessibilityWindowId + "/" + AccessibilityNodeInfo.idToString(accessibilityNodeId); @@ -829,6 +850,60 @@ public final class AccessibilityInteractionClient } /** + * {@inheritDoc} + */ + @Override + public void setPrefetchAccessibilityNodeInfoResult(@NonNull List<AccessibilityNodeInfo> infos, + int interactionId) { + List<AccessibilityNodeInfo> infosCopy = null; + int mConnectionIdWaitingForPrefetchResultCopy = -1; + String[] mPackageNamesForNextPrefetchResultCopy = null; + + synchronized (mInstanceLock) { + if (!infos.isEmpty() && mInteractionIdWaitingForPrefetchResult == interactionId) { + if (mMainHandler != null) { + if (mPrefetchResultRunnable != null) { + mMainHandler.removeCallbacks(mPrefetchResultRunnable); + mPrefetchResultRunnable = null; + } + /** + * TODO(b/180957109): AccessibilityCache is prone to deadlocks + * We post caching the prefetched nodes in the main thread. Using the binder + * thread results in "Long monitor contention with owner main" logs where + * service response times may exceed 5 seconds. This is due to the cache calling + * out to the system when refreshing nodes with the lock held. + */ + mPrefetchResultRunnable = () -> finalizeAndCacheAccessibilityNodeInfos( + infos, mConnectionIdWaitingForPrefetchResult, false, + mPackageNamesForNextPrefetchResult); + mMainHandler.post(mPrefetchResultRunnable); + + } else { + for (AccessibilityNodeInfo info : infos) { + infosCopy.add(new AccessibilityNodeInfo(info)); + } + mConnectionIdWaitingForPrefetchResultCopy = + mConnectionIdWaitingForPrefetchResult; + mPackageNamesForNextPrefetchResultCopy = + new String[mPackageNamesForNextPrefetchResult.length]; + for (int i = 0; i < mPackageNamesForNextPrefetchResult.length; i++) { + mPackageNamesForNextPrefetchResultCopy[i] = + mPackageNamesForNextPrefetchResult[i]; + + } + } + } + + } + + if (infosCopy != null) { + finalizeAndCacheAccessibilityNodeInfos( + infosCopy, mConnectionIdWaitingForPrefetchResultCopy, false, + mPackageNamesForNextPrefetchResultCopy); + } + } + + /** * Gets the result of a request to perform an accessibility action. * * @param interactionId The interaction id to match the result with the request. diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl index 049bb31adbb1..231e75a19a06 100644 --- a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl +++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl @@ -47,6 +47,15 @@ oneway interface IAccessibilityInteractionConnectionCallback { int interactionId); /** + * Sets the result of a prefetch request that returns {@link AccessibilityNodeInfo}s. + * + * @param root The {@link AccessibilityNodeInfo} for which the prefetching is based off of. + * @param infos The result {@link AccessibilityNodeInfo}s. + */ + void setPrefetchAccessibilityNodeInfoResult( + in List<AccessibilityNodeInfo> infos, int interactionId); + + /** * Sets the result of a request to perform an accessibility action. * * @param Whether the action was performed. diff --git a/core/java/android/view/translation/TranslationSpec.java b/core/java/android/view/translation/TranslationSpec.java index ab1bc477e0fd..16418a78f2c1 100644 --- a/core/java/android/view/translation/TranslationSpec.java +++ b/core/java/android/view/translation/TranslationSpec.java @@ -28,7 +28,7 @@ import com.android.internal.util.DataClass; * <p>This spec help specify information such as the language/locale for the translation, as well * as the data format for the translation (text, audio, etc.)</p> */ -@DataClass(genEqualsHashCode = true, genHiddenConstDefs = true) +@DataClass(genEqualsHashCode = true, genHiddenConstDefs = true, genToString = true) public final class TranslationSpec implements Parcelable { /** Data format for translation is text. */ @@ -99,6 +99,18 @@ public final class TranslationSpec implements Parcelable { @Override @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "TranslationSpec { " + + "language = " + mLanguage + ", " + + "dataFormat = " + mDataFormat + + " }"; + } + + @Override + @DataClass.Generated.Member public boolean equals(@android.annotation.Nullable Object o) { // You can override field equality logic by defining either of the methods like: // boolean fieldNameEquals(TranslationSpec other) { ... } @@ -175,10 +187,10 @@ public final class TranslationSpec implements Parcelable { }; @DataClass.Generated( - time = 1609964630624L, + time = 1614326090637L, codegenVersion = "1.0.22", sourceFile = "frameworks/base/core/java/android/view/translation/TranslationSpec.java", - inputSignatures = "public static final int DATA_FORMAT_TEXT\nprivate final @android.annotation.NonNull java.lang.String mLanguage\nprivate final @android.view.translation.TranslationSpec.DataFormat int mDataFormat\nclass TranslationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genHiddenConstDefs=true)") + inputSignatures = "public static final int DATA_FORMAT_TEXT\nprivate final @android.annotation.NonNull java.lang.String mLanguage\nprivate final @android.view.translation.TranslationSpec.DataFormat int mDataFormat\nclass TranslationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genHiddenConstDefs=true, genToString=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/view/translation/Translator.java b/core/java/android/view/translation/Translator.java index 22c3e57ecc95..163f832882c5 100644 --- a/core/java/android/view/translation/Translator.java +++ b/core/java/android/view/translation/Translator.java @@ -35,6 +35,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.os.IResultReceiver; import com.android.internal.util.SyncResultReceiver; +import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -221,6 +222,12 @@ public class Translator { return mId; } + /** @hide */ + public void dump(@NonNull String prefix, @NonNull PrintWriter pw) { + pw.print(prefix); pw.print("sourceSpec: "); pw.println(mSourceSpec); + pw.print(prefix); pw.print("destSpec: "); pw.println(mDestSpec); + } + /** * Requests a translation for the provided {@link TranslationRequest} using the Translator's * source spec and destination spec. diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java index b1e45bbcd875..81006121bdef 100644 --- a/core/java/android/view/translation/UiTranslationController.java +++ b/core/java/android/view/translation/UiTranslationController.java @@ -40,6 +40,7 @@ import android.view.translation.UiTranslationManager.UiTranslationState; import com.android.internal.util.function.pooled.PooledLambda; +import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -133,6 +134,23 @@ public class UiTranslationController { } /** + * Called to dump the translation information for Activity. + */ + public void dump(String outerPrefix, PrintWriter pw) { + pw.print(outerPrefix); pw.println("UiTranslationController:"); + final String pfx = outerPrefix + " "; + pw.print(pfx); pw.print("activity: "); pw.println(mActivity); + final int translatorSize = mTranslators.size(); + pw.print(outerPrefix); pw.print("number translator: "); pw.println(translatorSize); + for (int i = 0; i < translatorSize; i++) { + pw.print(outerPrefix); pw.print("#"); pw.println(i); + final Translator translator = mTranslators.valueAt(i); + translator.dump(outerPrefix, pw); + pw.println(); + } + } + + /** * The method is used by {@link Translator}, it will be called when the translation is done. The * translation result can be get from here. */ diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index e0b4ec71b0a0..2cf50bbc6793 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -705,6 +705,14 @@ public class RemoteViews implements Parcelable, Filter { public String getPackageName() { return mContextForResources.getPackageName(); } + + @Override + public boolean isRestricted() { + // Override isRestricted and direct to resource's implementation. The isRestricted is + // used for determining the risky resources loading, e.g. fonts, thus direct to context + // for resource. + return mContextForResources.isRestricted(); + } } private class SetEmptyView extends Action { diff --git a/core/java/com/android/internal/net/NetworkUtilsInternal.java b/core/java/com/android/internal/net/NetworkUtilsInternal.java index 571d7e721094..052959abff69 100644 --- a/core/java/com/android/internal/net/NetworkUtilsInternal.java +++ b/core/java/com/android/internal/net/NetworkUtilsInternal.java @@ -22,6 +22,8 @@ import static android.system.OsConstants.AF_INET6; import android.annotation.NonNull; import android.system.Os; +import java.io.FileDescriptor; + /** @hide */ public class NetworkUtilsInternal { @@ -36,6 +38,20 @@ public class NetworkUtilsInternal { public static native void setAllowNetworkingForProcess(boolean allowNetworking); /** + * Protect {@code fd} from VPN connections. After protecting, data sent through + * this socket will go directly to the underlying network, so its traffic will not be + * forwarded through the VPN. + */ + public static native boolean protectFromVpn(FileDescriptor fd); + + /** + * Protect {@code socketfd} from VPN connections. After protecting, data sent through + * this socket will go directly to the underlying network, so its traffic will not be + * forwarded through the VPN. + */ + public static native boolean protectFromVpn(int socketfd); + + /** * Returns true if the hostname is weakly validated. * @param hostname Name of host to validate. * @return True if it's a valid-ish hostname. diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index 58df2be2b944..bac6bbe43c91 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -1234,8 +1234,7 @@ public class SystemConfig { final int incrementalVersion = IncrementalManager.getVersion(); if (incrementalVersion > 0) { - addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY, 0); - addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY_VERSION, incrementalVersion); + addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY, incrementalVersion); } if (PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT) { diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 2287900795a5..d6d33873adaa 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -51,6 +51,7 @@ cc_library_shared { "android_util_XmlBlock.cpp", "android_util_jar_StrictJarFile.cpp", "com_android_internal_util_VirtualRefBasePtr.cpp", + ":deviceproductinfoconstants_aidl", ], include_dirs: [ @@ -150,7 +151,7 @@ cc_library_shared { "android_os_VintfRuntimeInfo.cpp", "android_os_incremental_IncrementalManager.cpp", "android_net_LocalSocketImpl.cpp", - "android_net_NetUtils.cpp", + "android_net_NetworkUtils.cpp", "android_service_DataLoaderService.cpp", "android_util_AssetManager.cpp", "android_util_Binder.cpp", diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp index c7439f1b32d4..b0c575162b56 100644 --- a/core/jni/android_content_res_ApkAssets.cpp +++ b/core/jni/android_content_res_ApkAssets.cpp @@ -83,6 +83,10 @@ class LoaderAssetsProvider : public AssetsProvider { return true; } + std::optional<std::string_view> GetPath() const override { + return {}; + } + const std::string& GetDebugName() const override { return debug_name_; } @@ -358,8 +362,16 @@ static jlong NativeGetFinalizer(JNIEnv* /*env*/, jclass /*clazz*/) { } static jstring NativeGetAssetPath(JNIEnv* env, jclass /*clazz*/, jlong ptr) { - const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr); - return env->NewStringUTF(apk_assets->GetPath().c_str()); + auto apk_assets = reinterpret_cast<const ApkAssets*>(ptr); + if (auto path = apk_assets->GetPath()) { + return env->NewStringUTF(path->data()); + } + return nullptr; +} + +static jstring NativeGetDebugName(JNIEnv* env, jclass /*clazz*/, jlong ptr) { + auto apk_assets = reinterpret_cast<const ApkAssets*>(ptr); + return env->NewStringUTF(apk_assets->GetDebugName().c_str()); } static jlong NativeGetStringBlock(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) { @@ -467,6 +479,7 @@ static const JNINativeMethod gApkAssetsMethods[] = { (void*)NativeLoadFromFdOffset}, {"nativeGetFinalizer", "()J", (void*)NativeGetFinalizer}, {"nativeGetAssetPath", "(J)Ljava/lang/String;", (void*)NativeGetAssetPath}, + {"nativeGetDebugName", "(J)Ljava/lang/String;", (void*)NativeGetDebugName}, {"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock}, {"nativeIsUpToDate", "(J)Z", (void*)NativeIsUpToDate}, {"nativeOpenXml", "(JLjava/lang/String;)J", (void*)NativeOpenXml}, diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetworkUtils.cpp index e2af87ee1adf..750810840bde 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetworkUtils.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "NetUtils" +#define LOG_TAG "NetworkUtils" #include <vector> @@ -123,15 +123,6 @@ static jint android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, job return setNetworkForSocket(netId, AFileDescriptor_getFD(env, javaFd)); } -static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint socket) -{ - return (jboolean) !protectFromVpn(socket); -} - -static jboolean android_net_utils_protectFromVpnWithFd(JNIEnv *env, jobject thiz, jobject javaFd) { - return android_net_utils_protectFromVpn(env, thiz, AFileDescriptor_getFD(env, javaFd)); -} - static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jint uid, jint netId) { return (jboolean) !queryUserAccess(uid, netId); @@ -276,8 +267,6 @@ static const JNINativeMethod gNetworkUtilMethods[] = { { "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess }, { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution }, { "bindSocketToNetwork", "(Ljava/io/FileDescriptor;I)I", (void*) android_net_utils_bindSocketToNetwork }, - { "protectFromVpn", "(I)Z", (void*) android_net_utils_protectFromVpn }, - { "protectFromVpn", "(Ljava/io/FileDescriptor;)Z", (void*) android_net_utils_protectFromVpnWithFd }, { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess }, { "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter }, { "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter }, diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 451ea93349f7..cbf4481bd2f1 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -27,6 +27,7 @@ #include <android-base/chrono_utils.h> #include <android/graphics/region.h> #include <android/gui/BnScreenCaptureListener.h> +#include <android/hardware/display/IDeviceProductInfoConstants.h> #include <android/os/IInputConstants.h> #include <android_runtime/AndroidRuntime.h> #include <android_runtime/android_hardware_HardwareBuffer.h> @@ -1022,16 +1023,24 @@ static jobject convertDeviceProductInfoToJavaObject( } else { LOG_FATAL("Unknown alternative for variant DeviceProductInfo::ManufactureOrModelDate"); } - auto relativeAddress = env->NewIntArray(info->relativeAddress.size()); - auto relativeAddressData = env->GetIntArrayElements(relativeAddress, nullptr); - for (int i = 0; i < info->relativeAddress.size(); i++) { - relativeAddressData[i] = info->relativeAddress[i]; + jint connectionToSinkType; + // Relative address maps to HDMI physical address. All addresses are 4 digits long allowing + // for a 5–device-deep hierarchy. For more information, refer: + // Section 8.7 - Physical Address of HDMI Specification Version 1.3a + using android::hardware::display::IDeviceProductInfoConstants; + if (info->relativeAddress.size() != 4) { + connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_UNKNOWN; + } else if (info->relativeAddress[0] == 0) { + connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_BUILT_IN; + } else if (info->relativeAddress[1] == 0) { + connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_DIRECT; + } else { + connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_TRANSITIVE; } - env->ReleaseIntArrayElements(relativeAddress, relativeAddressData, 0); return env->NewObject(gDeviceProductInfoClassInfo.clazz, gDeviceProductInfoClassInfo.ctor, name, manufacturerPnpId, productId, modelYear, manufactureDate, - relativeAddress); + connectionToSinkType); } static jobject nativeGetStaticDisplayInfo(JNIEnv* env, jclass clazz, jobject tokenObj) { @@ -1970,7 +1979,7 @@ int register_android_view_SurfaceControl(JNIEnv* env) "Ljava/lang/String;" "Ljava/lang/Integer;" "Landroid/hardware/display/DeviceProductInfo$ManufactureDate;" - "[I)V"); + "I)V"); jclass deviceProductInfoManufactureDateClazz = FindClassOrDie(env, "android/hardware/display/DeviceProductInfo$ManufactureDate"); diff --git a/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp b/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp index 10fc18dcd386..980e12d0bb40 100644 --- a/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp +++ b/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include <android/file_descriptor_jni.h> + #include "NetdClient.h" #include "core_jni_helpers.h" #include "jni.h" @@ -24,9 +26,20 @@ static void android_net_utils_setAllowNetworkingForProcess(JNIEnv *env, jobject setAllowNetworkingForProcess(hasConnectivity == JNI_TRUE); } +static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint socket) { + return (jboolean)!protectFromVpn(socket); +} + +static jboolean android_net_utils_protectFromVpnWithFd(JNIEnv *env, jobject thiz, jobject javaFd) { + return android_net_utils_protectFromVpn(env, thiz, AFileDescriptor_getFD(env, javaFd)); +} + static const JNINativeMethod gNetworkUtilMethods[] = { {"setAllowNetworkingForProcess", "(Z)V", (void *)android_net_utils_setAllowNetworkingForProcess}, + {"protectFromVpn", "(I)Z", (void *)android_net_utils_protectFromVpn}, + {"protectFromVpn", "(Ljava/io/FileDescriptor;)Z", + (void *)android_net_utils_protectFromVpnWithFd}, }; int register_com_android_internal_net_NetworkUtilsInternal(JNIEnv *env) { diff --git a/core/proto/OWNERS b/core/proto/OWNERS index 99fd21592411..e62b5c102a59 100644 --- a/core/proto/OWNERS +++ b/core/proto/OWNERS @@ -15,6 +15,7 @@ per-file settings_enums.proto=tmfang@google.com ogunwale@google.com jjaggi@google.com roosa@google.com +per-file package_item_info.proto = toddke@google.com per-file usagestatsservice.proto, usagestatsservice_v2.proto = mwachens@google.com per-file apphibernationservice.proto = file:/core/java/android/apphibernation/OWNERS diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 12cb3980f785..359bb69a417e 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -848,6 +848,15 @@ <!-- y-intercept --> <item>1.000000000000000</item> </string-array> + <!-- Default strength, in percentage, of bright color reduction when activated. --> + <integer name="config_reduceBrightColorsStrengthDefault">0</integer> + + <!-- Minimum strength, in percentage, supported by bright color reduction. --> + <integer name="config_reduceBrightColorsStrengthMin">0</integer> + + <!-- Maximum strength, in percentage, supported by bright color reduction. --> + <integer name="config_reduceBrightColorsStrengthMax">100</integer> + <!-- Boolean indicating whether display white balance is supported. --> <bool name="config_displayWhiteBalanceAvailable">false</bool> @@ -1783,7 +1792,7 @@ * SDK level 28 makes the following algorithms mandatory : "cbc(aes)", "hmac(md5)", "hmac(sha1)", "hmac(sha256)", "hmac(sha384)", "hmac(sha512)", "rfc4106(gcm(aes))" * SDK level 31 makes the following algorithms mandatory : "rfc3686(ctr(aes))", - "xcbc(aes)", "rfc7539esp(chacha20,poly1305)" + "xcbc(aes)", "cmac(aes)", "rfc7539esp(chacha20,poly1305)" --> <string-array name="config_optionalIpSecAlgorithms" translatable="false"> <!-- Add algorithm here --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index dbb584dfe293..5d56eb760679 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3224,6 +3224,9 @@ <java-symbol type="bool" name="config_reduceBrightColorsAvailable" /> <java-symbol type="array" name="config_reduceBrightColorsCoefficients" /> <java-symbol type="array" name="config_reduceBrightColorsCoefficientsNonlinear" /> + <java-symbol type="integer" name="config_reduceBrightColorsStrengthDefault" /> + <java-symbol type="integer" name="config_reduceBrightColorsStrengthMin" /> + <java-symbol type="integer" name="config_reduceBrightColorsStrengthMax" /> <java-symbol type="array" name="config_availableColorModes" /> <java-symbol type="array" name="config_mappedColorModes" /> <java-symbol type="string" name="config_vendorColorModesRestoreHint" /> diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java index ab24f89015c7..7e1e7f4bdd7f 100644 --- a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java +++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java @@ -33,9 +33,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import java.util.Arrays; -import java.util.List; - /** * Tests for AccessibilityInteractionClient */ @@ -65,7 +62,7 @@ public class AccessibilityInteractionClientTest { final long accessibilityNodeId = 0x4321L; AccessibilityNodeInfo nodeFromConnection = AccessibilityNodeInfo.obtain(); nodeFromConnection.setSourceNodeId(accessibilityNodeId, windowId); - mMockConnection.mInfosToReturn = Arrays.asList(nodeFromConnection); + mMockConnection.mInfoToReturn = nodeFromConnection; AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); AccessibilityNodeInfo node = client.findAccessibilityNodeInfoByAccessibilityId( MOCK_CONNECTION_ID, windowId, accessibilityNodeId, true, 0, null); @@ -75,7 +72,7 @@ public class AccessibilityInteractionClientTest { } private static class MockConnection extends AccessibilityServiceConnectionImpl { - List<AccessibilityNodeInfo> mInfosToReturn; + AccessibilityNodeInfo mInfoToReturn; @Override public String[] findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId, @@ -83,7 +80,7 @@ public class AccessibilityInteractionClientTest { IAccessibilityInteractionConnectionCallback callback, int flags, long threadId, Bundle arguments) { try { - callback.setFindAccessibilityNodeInfosResult(mInfosToReturn, interactionId); + callback.setFindAccessibilityNodeInfoResult(mInfoToReturn, interactionId); } catch (RemoteException e) { throw new RuntimeException(e); } diff --git a/core/tests/coretests/src/android/view/accessibility/OWNERS b/core/tests/coretests/src/android/view/accessibility/OWNERS new file mode 100644 index 000000000000..b74281edbf52 --- /dev/null +++ b/core/tests/coretests/src/android/view/accessibility/OWNERS @@ -0,0 +1 @@ +include /core/java/android/view/accessibility/OWNERS diff --git a/data/etc/car/android.car.cluster.xml b/data/etc/car/android.car.cluster.xml index d7f29da7a356..de3accafa2fa 100644 --- a/data/etc/car/android.car.cluster.xml +++ b/data/etc/car/android.car.cluster.xml @@ -20,5 +20,7 @@ <permission name="android.permission.INTERACT_ACROSS_USERS"/> <permission name="android.permission.MANAGE_USERS"/> <permission name="android.permission.WRITE_SECURE_SETTINGS"/> + <permission name="android.car.permission.CAR_ENGINE_DETAILED"/> + <permission name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/> </privapp-permissions> </permissions> diff --git a/data/etc/car/com.android.car.bugreport.xml b/data/etc/car/com.android.car.bugreport.xml index c3642d886180..2ff98357f8bf 100644 --- a/data/etc/car/com.android.car.bugreport.xml +++ b/data/etc/car/com.android.car.bugreport.xml @@ -21,5 +21,6 @@ <permission name="android.permission.READ_LOGS"/> <permission name="android.permission.MANAGE_USERS"/> <permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/> + <permission name="android.car.permission.CAR_DRIVING_STATE"/> </privapp-permissions> </permissions> diff --git a/data/etc/car/com.android.car.carlauncher.xml b/data/etc/car/com.android.car.carlauncher.xml index 0e49284d106f..ac16af348471 100644 --- a/data/etc/car/com.android.car.carlauncher.xml +++ b/data/etc/car/com.android.car.carlauncher.xml @@ -17,9 +17,10 @@ <permissions> <privapp-permissions package="com.android.car.carlauncher"> <permission name="android.permission.ACTIVITY_EMBEDDING"/> - <permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/> + <permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/> <permission name="android.permission.MANAGE_USERS"/> <permission name="android.permission.MEDIA_CONTENT_CONTROL"/> <permission name="android.permission.PACKAGE_USAGE_STATS"/> + <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/> </privapp-permissions> </permissions> diff --git a/data/etc/car/com.android.car.dialer.xml b/data/etc/car/com.android.car.dialer.xml index d44f5a1704a2..61ae53a30209 100644 --- a/data/etc/car/com.android.car.dialer.xml +++ b/data/etc/car/com.android.car.dialer.xml @@ -18,5 +18,6 @@ <privapp-permissions package="com.android.car.dialer"> <permission name="android.permission.INTERACT_ACROSS_USERS"/> <permission name="android.permission.MODIFY_PHONE_STATE"/> + <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/> </privapp-permissions> </permissions> diff --git a/data/etc/car/com.android.car.hvac.xml b/data/etc/car/com.android.car.hvac.xml index d3631e067f8b..534d44da9a7c 100644 --- a/data/etc/car/com.android.car.hvac.xml +++ b/data/etc/car/com.android.car.hvac.xml @@ -17,5 +17,6 @@ <permissions> <privapp-permissions package="com.android.car.hvac"> <permission name="android.permission.INTERACT_ACROSS_USERS"/> + <permission name="android.car.permission.CONTROL_CAR_CLIMATE"/> </privapp-permissions> </permissions> diff --git a/data/etc/car/com.android.car.radio.xml b/data/etc/car/com.android.car.radio.xml index d7853aba2d90..ed8652c01647 100644 --- a/data/etc/car/com.android.car.radio.xml +++ b/data/etc/car/com.android.car.radio.xml @@ -18,5 +18,7 @@ <privapp-permissions package="com.android.car.radio"> <permission name="android.permission.ACCESS_BROADCAST_RADIO"/> <permission name="android.permission.MEDIA_CONTENT_CONTROL"/> + <permission name="android.car.permission.CAR_CONTROL_AUDIO_SETTINGS"/> + <permission name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/> </privapp-permissions> </permissions> diff --git a/data/etc/car/com.google.android.car.kitchensink.xml b/data/etc/car/com.google.android.car.kitchensink.xml index bd30d7a61517..e6196c296552 100644 --- a/data/etc/car/com.google.android.car.kitchensink.xml +++ b/data/etc/car/com.google.android.car.kitchensink.xml @@ -51,5 +51,41 @@ <!-- use for rotary fragment to enable/disable packages related to rotary --> <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/> + + <!-- CarService permissions --> + <!-- TODO: Explain why so many permissions are required --> + <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/> + <permission name="android.car.permission.CAR_CONTROL_AUDIO_SETTINGS"/> + <permission name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/> + <permission name="android.car.permission.CAR_DIAGNOSTICS"/> + <permission name="android.car.permission.CAR_DISPLAY_IN_CLUSTER"/> + <permission name="android.car.permission.CAR_DRIVING_STATE"/> + <permission name="android.car.permission.CAR_DYNAMICS_STATE"/> + <permission name="android.car.permission.CAR_EXTERIOR_LIGHTS"/> + <permission name="android.car.permission.CAR_IDENTIFICATION"/> + <permission name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/> + <permission name="android.car.permission.CAR_MILEAGE"/> + <permission name="android.car.permission.CAR_MOCK_VEHICLE_HAL"/> + <permission name="android.car.permission.CAR_NAVIGATION_MANAGER"/> + <permission name="android.car.permission.CAR_POWER"/> + <permission name="android.car.permission.CAR_PROJECTION"/> + <permission name="android.car.permission.CAR_TIRES"/> + <permission name="android.car.permission.CAR_TEST_SERVICE"/> + <permission name="android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION"/> + <permission name="android.car.permission.CAR_VENDOR_EXTENSION"/> + <permission name="android.car.permission.CONTROL_CAR_CLIMATE"/> + <permission name="android.car.permission.CONTROL_CAR_DOORS"/> + <permission name="android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS"/> + <permission name="android.car.permission.CONTROL_CAR_FEATURES"/> + <permission name="android.car.permission.CONTROL_CAR_MIRRORS"/> + <permission name="android.car.permission.CONTROL_CAR_SEATS"/> + <permission name="android.car.permission.CONTROL_CAR_WINDOWS"/> + <permission name="android.car.permission.GET_CAR_VENDOR_CATEGORY_INFO"/> + <permission name="android.car.permission.GET_CAR_VENDOR_CATEGORY_SEAT"/> + <permission name="android.car.permission.READ_CAR_STEERING"/> + <permission name="android.car.permission.SET_CAR_VENDOR_CATEGORY_INFO"/> + <permission name="android.car.permission.STORAGE_MONITORING"/> + <permission name="android.car.permission.VMS_PUBLISHER"/> + <permission name="android.car.permission.VMS_SUBSCRIBER"/> </privapp-permissions> </permissions> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 5d4d7c3c4aa4..fae89d65ddd1 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -256,6 +256,7 @@ applications that come with the platform <!-- Permissions required for reading DeviceConfig --> <permission name="android.permission.READ_DEVICE_CONFIG" /> <permission name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"/> + <permission name="android.permission.MODIFY_QUIET_MODE"/> </privapp-permissions> <privapp-permissions package="com.android.providers.telephony"> @@ -483,6 +484,8 @@ applications that come with the platform <permission name="android.permission.SIGNAL_REBOOT_READINESS" /> <!-- Permission required for CTS test - PeopleManagerTest --> <permission name="android.permission.READ_PEOPLE_DATA" /> + <!-- Permission required for CTS test - UiTranslationManagerTest --> + <permission name="android.permission.MANAGE_UI_TRANSLATION" /> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java index 32f3648be19a..c6d994ecde8d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java @@ -280,7 +280,7 @@ class SizeCompatUILayout { : stableBounds.right - taskBounds.left - mButtonSize; final int positionY = stableBounds.bottom - taskBounds.top - mButtonSize; - mSyncQueue.runInSync(t -> t.setPosition(leash, positionX, positionY)); + updateSurfacePosition(leash, positionX, positionY); } void updateHintSurfacePosition() { @@ -303,7 +303,16 @@ class SizeCompatUILayout { final int positionY = stableBounds.bottom - taskBounds.top - mPopupOffsetY - mHint.getMeasuredHeight(); - mSyncQueue.runInSync(t -> t.setPosition(leash, positionX, positionY)); + updateSurfacePosition(leash, positionX, positionY); + } + + private void updateSurfacePosition(SurfaceControl leash, int positionX, int positionY) { + mSyncQueue.runInSync(t -> { + t.setPosition(leash, positionX, positionY); + // The size compat UI should be the topmost child of the Task in case there can be more + // than one children. + t.setLayer(leash, Integer.MAX_VALUE); + }); } int getDisplayId() { diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp index 9c743cea592a..76366fce2aea 100755 --- a/libs/androidfw/ApkAssets.cpp +++ b/libs/androidfw/ApkAssets.cpp @@ -156,7 +156,11 @@ std::unique_ptr<ApkAssets> ApkAssets::LoadImpl(std::unique_ptr<Asset> resources_ std::move(loaded_idmap))); } -const std::string& ApkAssets::GetPath() const { +std::optional<std::string_view> ApkAssets::GetPath() const { + return assets_provider_->GetPath(); +} + +const std::string& ApkAssets::GetDebugName() const { return assets_provider_->GetDebugName(); } diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 36bde5ccf267..c0ef7be8b673 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -116,8 +116,10 @@ void AssetManager2::BuildDynamicRefTable() { package_groups_.clear(); package_ids_.fill(0xff); - // A mapping from apk assets path to the runtime package id of its first loaded package. - std::unordered_map<std::string, uint8_t> apk_assets_package_ids; + // A mapping from path of apk assets that could be target packages of overlays to the runtime + // package id of its first loaded package. Overlays currently can only override resources in the + // first package in the target resource table. + std::unordered_map<std::string, uint8_t> target_assets_package_ids; // Overlay resources are not directly referenced by an application so their resource ids // can change throughout the application's lifetime. Assign overlay package ids last. @@ -140,8 +142,8 @@ void AssetManager2::BuildDynamicRefTable() { if (auto loaded_idmap = apk_assets->GetLoadedIdmap(); loaded_idmap != nullptr) { // The target package must precede the overlay package in the apk assets paths in order // to take effect. - auto iter = apk_assets_package_ids.find(std::string(loaded_idmap->TargetApkPath())); - if (iter == apk_assets_package_ids.end()) { + auto iter = target_assets_package_ids.find(std::string(loaded_idmap->TargetApkPath())); + if (iter == target_assets_package_ids.end()) { LOG(INFO) << "failed to find target package for overlay " << loaded_idmap->OverlayApkPath(); } else { @@ -205,7 +207,10 @@ void AssetManager2::BuildDynamicRefTable() { package_name, static_cast<uint8_t>(entry.package_id)); } - apk_assets_package_ids.insert(std::make_pair(apk_assets->GetPath(), package_id)); + if (auto apk_assets_path = apk_assets->GetPath()) { + // Overlay target ApkAssets must have been created using path based load apis. + target_assets_package_ids.insert(std::make_pair(std::string(*apk_assets_path), package_id)); + } } } @@ -227,7 +232,7 @@ void AssetManager2::DumpToLog() const { std::string list; for (const auto& apk_assets : apk_assets_) { - base::StringAppendF(&list, "%s,", apk_assets->GetPath().c_str()); + base::StringAppendF(&list, "%s,", apk_assets->GetDebugName().c_str()); } LOG(INFO) << "ApkAssets: " << list; @@ -383,8 +388,8 @@ void AssetManager2::SetConfiguration(const ResTable_config& configuration) { } } -std::set<std::string> AssetManager2::GetNonSystemOverlayPaths() const { - std::set<std::string> non_system_overlays; +std::set<const ApkAssets*> AssetManager2::GetNonSystemOverlays() const { + std::set<const ApkAssets*> non_system_overlays; for (const PackageGroup& package_group : package_groups_) { bool found_system_package = false; for (const ConfiguredPackage& package : package_group.packages_) { @@ -396,7 +401,7 @@ std::set<std::string> AssetManager2::GetNonSystemOverlayPaths() const { if (!found_system_package) { for (const ConfiguredOverlay& overlay : package_group.overlays_) { - non_system_overlays.insert(apk_assets_[overlay.cookie]->GetPath()); + non_system_overlays.insert(apk_assets_[overlay.cookie]); } } } @@ -408,7 +413,7 @@ base::expected<std::set<ResTable_config>, IOError> AssetManager2::GetResourceCon bool exclude_system, bool exclude_mipmap) const { ATRACE_NAME("AssetManager::GetResourceConfigurations"); const auto non_system_overlays = - (exclude_system) ? GetNonSystemOverlayPaths() : std::set<std::string>(); + (exclude_system) ? GetNonSystemOverlays() : std::set<const ApkAssets*>(); std::set<ResTable_config> configurations; for (const PackageGroup& package_group : package_groups_) { @@ -419,8 +424,8 @@ base::expected<std::set<ResTable_config>, IOError> AssetManager2::GetResourceCon } auto apk_assets = apk_assets_[package_group.cookies_[i]]; - if (exclude_system && apk_assets->IsOverlay() - && non_system_overlays.find(apk_assets->GetPath()) == non_system_overlays.end()) { + if (exclude_system && apk_assets->IsOverlay() && + non_system_overlays.find(apk_assets) == non_system_overlays.end()) { // Exclude overlays that target system resources. continue; } @@ -439,7 +444,7 @@ std::set<std::string> AssetManager2::GetResourceLocales(bool exclude_system, ATRACE_NAME("AssetManager::GetResourceLocales"); std::set<std::string> locales; const auto non_system_overlays = - (exclude_system) ? GetNonSystemOverlayPaths() : std::set<std::string>(); + (exclude_system) ? GetNonSystemOverlays() : std::set<const ApkAssets*>(); for (const PackageGroup& package_group : package_groups_) { for (size_t i = 0; i < package_group.packages_.size(); i++) { @@ -449,8 +454,8 @@ std::set<std::string> AssetManager2::GetResourceLocales(bool exclude_system, } auto apk_assets = apk_assets_[package_group.cookies_[i]]; - if (exclude_system && apk_assets->IsOverlay() - && non_system_overlays.find(apk_assets->GetPath()) == non_system_overlays.end()) { + if (exclude_system && apk_assets->IsOverlay() && + non_system_overlays.find(apk_assets) == non_system_overlays.end()) { // Exclude overlays that target system resources. continue; } @@ -491,7 +496,7 @@ std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) con AssetDir::FileInfo info; info.setFileName(String8(name.data(), name.size())); info.setFileType(type); - info.setSourceName(String8(apk_assets->GetPath().c_str())); + info.setSourceName(String8(apk_assets->GetDebugName().c_str())); files->add(info); }; @@ -846,7 +851,7 @@ std::string AssetManager2::GetLastResourceResolution() const { } log_stream << "\n\t" << prefix->second << ": " << *step.package_name << " (" - << apk_assets_[step.cookie]->GetPath() << ")"; + << apk_assets_[step.cookie]->GetDebugName() << ")"; if (!step.config_name.isEmpty()) { log_stream << " -" << step.config_name; } @@ -1556,41 +1561,32 @@ base::expected<std::monostate, IOError> Theme::SetTo(const Theme& o) { std::map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map; // Determine which ApkAssets are loaded in both theme AssetManagers. - std::vector<const ApkAssets*> src_assets = o.asset_manager_->GetApkAssets(); + const auto src_assets = o.asset_manager_->GetApkAssets(); for (size_t i = 0; i < src_assets.size(); i++) { const ApkAssets* src_asset = src_assets[i]; - std::vector<const ApkAssets*> dest_assets = asset_manager_->GetApkAssets(); + const auto dest_assets = asset_manager_->GetApkAssets(); for (size_t j = 0; j < dest_assets.size(); j++) { const ApkAssets* dest_asset = dest_assets[j]; + if (src_asset != dest_asset) { + // ResourcesManager caches and reuses ApkAssets when the same apk must be present in + // multiple AssetManagers. Two ApkAssets point to the same version of the same resources + // if they are the same instance. + continue; + } - // Map the runtime package of the source apk asset to the destination apk asset. - if (src_asset->GetPath() == dest_asset->GetPath()) { - const auto& src_packages = src_asset->GetLoadedArsc()->GetPackages(); - const auto& dest_packages = dest_asset->GetLoadedArsc()->GetPackages(); - - SourceToDestinationRuntimePackageMap package_map; - - // The source and destination package should have the same number of packages loaded in - // the same order. - const size_t N = src_packages.size(); - CHECK(N == dest_packages.size()) - << " LoadedArsc " << src_asset->GetPath() << " differs number of packages."; - for (size_t p = 0; p < N; p++) { - auto& src_package = src_packages[p]; - auto& dest_package = dest_packages[p]; - CHECK(src_package->GetPackageName() == dest_package->GetPackageName()) - << " Package " << src_package->GetPackageName() << " differs in load order."; - - int src_package_id = o.asset_manager_->GetAssignedPackageId(src_package.get()); - int dest_package_id = asset_manager_->GetAssignedPackageId(dest_package.get()); - package_map[src_package_id] = dest_package_id; - } - - src_to_dest_asset_cookies.insert(std::make_pair(i, j)); - src_asset_cookie_id_map.insert(std::make_pair(i, package_map)); - break; + // Map the package ids of the asset in the source AssetManager to the package ids of the + // asset in th destination AssetManager. + SourceToDestinationRuntimePackageMap package_map; + for (const auto& loaded_package : src_asset->GetLoadedArsc()->GetPackages()) { + const int src_package_id = o.asset_manager_->GetAssignedPackageId(loaded_package.get()); + const int dest_package_id = asset_manager_->GetAssignedPackageId(loaded_package.get()); + package_map[src_package_id] = dest_package_id; } + + src_to_dest_asset_cookies.insert(std::make_pair(i, j)); + src_asset_cookie_id_map.insert(std::make_pair(i, package_map)); + break; } } diff --git a/libs/androidfw/AssetsProvider.cpp b/libs/androidfw/AssetsProvider.cpp index f3c48f7f9fc8..0aaf0b359b60 100644 --- a/libs/androidfw/AssetsProvider.cpp +++ b/libs/androidfw/AssetsProvider.cpp @@ -261,6 +261,13 @@ std::optional<uint32_t> ZipAssetsProvider::GetCrc(std::string_view path) const { return entry.crc32; } +std::optional<std::string_view> ZipAssetsProvider::GetPath() const { + if (name_.GetPath() != nullptr) { + return *name_.GetPath(); + } + return {}; +} + const std::string& ZipAssetsProvider::GetDebugName() const { return name_.GetDebugName(); } @@ -318,6 +325,10 @@ bool DirectoryAssetsProvider::ForEachFile( return true; } +std::optional<std::string_view> DirectoryAssetsProvider::GetPath() const { + return dir_; +} + const std::string& DirectoryAssetsProvider::GetDebugName() const { return dir_; } @@ -336,13 +347,9 @@ MultiAssetsProvider::MultiAssetsProvider(std::unique_ptr<AssetsProvider>&& prima std::unique_ptr<AssetsProvider>&& secondary) : primary_(std::forward<std::unique_ptr<AssetsProvider>>(primary)), secondary_(std::forward<std::unique_ptr<AssetsProvider>>(secondary)) { - if (primary_->GetDebugName() == kEmptyDebugString) { - debug_name_ = secondary_->GetDebugName(); - } else if (secondary_->GetDebugName() == kEmptyDebugString) { - debug_name_ = primary_->GetDebugName(); - } else { - debug_name_ = primary_->GetDebugName() + " and " + secondary_->GetDebugName(); - } + debug_name_ = primary_->GetDebugName() + " and " + secondary_->GetDebugName(); + path_ = (primary_->GetDebugName() != kEmptyDebugString) ? primary_->GetPath() + : secondary_->GetPath(); } std::unique_ptr<AssetsProvider> MultiAssetsProvider::Create( @@ -367,6 +374,10 @@ bool MultiAssetsProvider::ForEachFile(const std::string& root_path, return primary_->ForEachFile(root_path, f) && secondary_->ForEachFile(root_path, f); } +std::optional<std::string_view> MultiAssetsProvider::GetPath() const { + return path_; +} + const std::string& MultiAssetsProvider::GetDebugName() const { return debug_name_; } @@ -394,6 +405,10 @@ bool EmptyAssetsProvider::ForEachFile( return true; } +std::optional<std::string_view> EmptyAssetsProvider::GetPath() const { + return {}; +} + const std::string& EmptyAssetsProvider::GetDebugName() const { const static std::string kEmpty = kEmptyDebugString; return kEmpty; diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h index d0019ed6be30..6f88f41976cd 100644 --- a/libs/androidfw/include/androidfw/ApkAssets.h +++ b/libs/androidfw/include/androidfw/ApkAssets.h @@ -34,7 +34,6 @@ namespace android { // Holds an APK. class ApkAssets { public: - // Creates an ApkAssets from a path on device. static std::unique_ptr<ApkAssets> Load(const std::string& path, package_property_t flags = 0U); @@ -61,12 +60,11 @@ class ApkAssets { static std::unique_ptr<ApkAssets> LoadOverlay(const std::string& idmap_path, package_property_t flags = 0U); - // TODO(177101983): Remove all uses of GetPath for checking whether two ApkAssets are the same. - // With the introduction of ResourcesProviders, not all ApkAssets have paths. This could cause - // bugs when path is used for comparison because multiple ApkAssets could have the same "firendly - // name". Use pointer equality instead. ResourceManager caches and reuses ApkAssets so the - // same asset should have the same pointer. - const std::string& GetPath() const; + // Path to the contents of the ApkAssets on disk. The path could represent an APk, a directory, + // or some other file type. + std::optional<std::string_view> GetPath() const; + + const std::string& GetDebugName() const; const AssetsProvider* GetAssetsProvider() const { return assets_provider_.get(); diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index 2255973f1039..119f531b8634 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -412,7 +412,7 @@ class AssetManager2 { void RebuildFilterList(); // Retrieves the APK paths of overlays that overlay non-system packages. - std::set<std::string> GetNonSystemOverlayPaths() const; + std::set<const ApkAssets*> GetNonSystemOverlays() const; // AssetManager2::GetBag(resid) wraps this function to track which resource ids have already // been seen while traversing bag parents. diff --git a/libs/androidfw/include/androidfw/AssetsProvider.h b/libs/androidfw/include/androidfw/AssetsProvider.h index 6f16ff453905..63bbdcc9698d 100644 --- a/libs/androidfw/include/androidfw/AssetsProvider.h +++ b/libs/androidfw/include/androidfw/AssetsProvider.h @@ -48,6 +48,10 @@ struct AssetsProvider { virtual bool ForEachFile(const std::string& path, const std::function<void(const StringPiece&, FileType)>& f) const = 0; + // Retrieves the path to the contents of the AssetsProvider on disk. The path could represent an + // APk, a directory, or some other file type. + WARN_UNUSED virtual std::optional<std::string_view> GetPath() const = 0; + // Retrieves a name that represents the interface. This may or may not be the path of the // interface source. WARN_UNUSED virtual const std::string& GetDebugName() const = 0; @@ -85,9 +89,9 @@ struct ZipAssetsProvider : public AssetsProvider { bool ForEachFile(const std::string& root_path, const std::function<void(const StringPiece&, FileType)>& f) const override; + WARN_UNUSED std::optional<std::string_view> GetPath() const override; WARN_UNUSED const std::string& GetDebugName() const override; WARN_UNUSED bool IsUpToDate() const override; - WARN_UNUSED std::optional<uint32_t> GetCrc(std::string_view path) const; ~ZipAssetsProvider() override = default; @@ -125,6 +129,7 @@ struct DirectoryAssetsProvider : public AssetsProvider { bool ForEachFile(const std::string& path, const std::function<void(const StringPiece&, FileType)>& f) const override; + WARN_UNUSED std::optional<std::string_view> GetPath() const override; WARN_UNUSED const std::string& GetDebugName() const override; WARN_UNUSED bool IsUpToDate() const override; @@ -149,6 +154,7 @@ struct MultiAssetsProvider : public AssetsProvider { bool ForEachFile(const std::string& root_path, const std::function<void(const StringPiece&, FileType)>& f) const override; + WARN_UNUSED std::optional<std::string_view> GetPath() const override; WARN_UNUSED const std::string& GetDebugName() const override; WARN_UNUSED bool IsUpToDate() const override; @@ -163,6 +169,7 @@ struct MultiAssetsProvider : public AssetsProvider { std::unique_ptr<AssetsProvider> primary_; std::unique_ptr<AssetsProvider> secondary_; + std::optional<std::string_view> path_; std::string debug_name_; }; @@ -173,6 +180,7 @@ struct EmptyAssetsProvider : public AssetsProvider { bool ForEachFile(const std::string& path, const std::function<void(const StringPiece&, FileType)>& f) const override; + WARN_UNUSED std::optional<std::string_view> GetPath() const override; WARN_UNUSED const std::string& GetDebugName() const override; WARN_UNUSED bool IsUpToDate() const override; diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java index e620dfbafa08..8b448877c15b 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java @@ -107,12 +107,10 @@ public class CompanionDeviceDiscoveryService extends Service { String callingPackage, IFindDeviceCallback findCallback, AndroidFuture serviceCallback) { - if (DEBUG) { - Log.i(LOG_TAG, - "startDiscovery() called with: filter = [" + request - + "], findCallback = [" + findCallback + "]" - + "], serviceCallback = [" + serviceCallback + "]"); - } + Log.i(LOG_TAG, + "startDiscovery() called with: filter = [" + request + + "], findCallback = [" + findCallback + "]" + + "], serviceCallback = [" + serviceCallback + "]"); mFindCallback = findCallback; mServiceCallback = serviceCallback; Handler.getMain().sendMessage(obtainMessage( @@ -127,7 +125,7 @@ public class CompanionDeviceDiscoveryService extends Service { @Override public IBinder onBind(Intent intent) { - if (DEBUG) Log.i(LOG_TAG, "onBind(" + intent + ")"); + Log.i(LOG_TAG, "onBind(" + intent + ")"); return mBinder.asBinder(); } @@ -135,7 +133,7 @@ public class CompanionDeviceDiscoveryService extends Service { public void onCreate() { super.onCreate(); - if (DEBUG) Log.i(LOG_TAG, "onCreate()"); + Log.i(LOG_TAG, "onCreate()"); mBluetoothManager = getSystemService(BluetoothManager.class); mBluetoothAdapter = mBluetoothManager.getAdapter(); @@ -160,7 +158,9 @@ public class CompanionDeviceDiscoveryService extends Service { = CollectionUtils.map(mBLEFilters, BluetoothLeDeviceFilter::getScanFilter); reset(); - } else if (DEBUG) Log.i(LOG_TAG, "startDiscovery: duplicate request: " + request); + } else { + Log.i(LOG_TAG, "startDiscovery: duplicate request: " + request); + } if (!ArrayUtils.isEmpty(mDevicesFound)) { onReadyToShowUI(); @@ -197,17 +197,20 @@ public class CompanionDeviceDiscoveryService extends Service { final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothDevice.ACTION_FOUND); + Log.i(LOG_TAG, "registerReceiver(BluetoothDevice.ACTION_FOUND)"); mBluetoothBroadcastReceiver = new BluetoothBroadcastReceiver(); registerReceiver(mBluetoothBroadcastReceiver, intentFilter); mBluetoothAdapter.startDiscovery(); } if (shouldScan(mBLEFilters) && mBLEScanner != null) { + Log.i(LOG_TAG, "BLEScanner.startScan"); mBLEScanCallback = new BLEScanCallback(); mBLEScanner.startScan(mBLEScanFilters, mDefaultScanSettings, mBLEScanCallback); } if (shouldScan(mWifiFilters)) { + Log.i(LOG_TAG, "registerReceiver(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)"); mWifiBroadcastReceiver = new WifiBroadcastReceiver(); registerReceiver(mWifiBroadcastReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); @@ -225,7 +228,7 @@ public class CompanionDeviceDiscoveryService extends Service { @MainThread private void reset() { - if (DEBUG) Log.i(LOG_TAG, "reset()"); + Log.i(LOG_TAG, "reset()"); stopScan(); mDevicesFound.clear(); mSelectedDevice = null; @@ -234,12 +237,13 @@ public class CompanionDeviceDiscoveryService extends Service { @Override public boolean onUnbind(Intent intent) { + Log.i(LOG_TAG, "onUnbind(intent = " + intent + ")"); stopScan(); return super.onUnbind(intent); } private void stopScan() { - if (DEBUG) Log.i(LOG_TAG, "stopScan()"); + Log.i(LOG_TAG, "stopScan()"); if (!mIsScanning) return; mIsScanning = false; diff --git a/core/java/android/net/QosFilterParcelable.aidl b/packages/Connectivity/framework/aidl-export/android/net/QosFilterParcelable.aidl index 312d6352ee92..312d6352ee92 100644 --- a/core/java/android/net/QosFilterParcelable.aidl +++ b/packages/Connectivity/framework/aidl-export/android/net/QosFilterParcelable.aidl diff --git a/core/java/android/net/QosSession.aidl b/packages/Connectivity/framework/aidl-export/android/net/QosSession.aidl index c2cf36624b55..c2cf36624b55 100644 --- a/core/java/android/net/QosSession.aidl +++ b/packages/Connectivity/framework/aidl-export/android/net/QosSession.aidl diff --git a/core/java/android/net/QosSocketInfo.aidl b/packages/Connectivity/framework/aidl-export/android/net/QosSocketInfo.aidl index 476c0900e23e..476c0900e23e 100644 --- a/core/java/android/net/QosSocketInfo.aidl +++ b/packages/Connectivity/framework/aidl-export/android/net/QosSocketInfo.aidl diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt index 31b8fc8ae53a..a8f1a4d2a7f8 100644 --- a/packages/Connectivity/framework/api/current.txt +++ b/packages/Connectivity/framework/api/current.txt @@ -401,16 +401,6 @@ package android.net { method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier); } - public final class Proxy { - ctor public Proxy(); - method @Deprecated public static String getDefaultHost(); - method @Deprecated public static int getDefaultPort(); - method @Deprecated public static String getHost(android.content.Context); - method @Deprecated public static int getPort(android.content.Context); - field @Deprecated public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO"; - field public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE"; - } - public class ProxyInfo implements android.os.Parcelable { ctor public ProxyInfo(@Nullable android.net.ProxyInfo); method public static android.net.ProxyInfo buildDirectProxy(String, int); diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt index 3af855ec1e11..a9fd6f248560 100644 --- a/packages/Connectivity/framework/api/module-lib-current.txt +++ b/packages/Connectivity/framework/api/module-lib-current.txt @@ -23,10 +23,6 @@ package android.net { field public static final int TRANSPORT_TEST = 7; // 0x7 } - public final class Proxy { - method public static void setHttpProxyConfiguration(@Nullable android.net.ProxyInfo); - } - public final class TcpRepairWindow { ctor public TcpRepairWindow(int, int, int, int, int, int); field public final int maxWindow; diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt index 41ebc5774f3d..373fa3c24027 100644 --- a/packages/Connectivity/framework/api/system-current.txt +++ b/packages/Connectivity/framework/api/system-current.txt @@ -308,6 +308,9 @@ package android.net { field public static final int ID_NONE = -1; // 0xffffffff } + public class NetworkReleasedException extends java.lang.Exception { + } + public class NetworkRequest implements android.os.Parcelable { method @Nullable public String getRequestorPackageName(); method public int getRequestorUid(); @@ -317,6 +320,47 @@ package android.net { method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int); } + public abstract class QosCallback { + ctor public QosCallback(); + method public void onError(@NonNull android.net.QosCallbackException); + method public void onQosSessionAvailable(@NonNull android.net.QosSession, @NonNull android.net.QosSessionAttributes); + method public void onQosSessionLost(@NonNull android.net.QosSession); + } + + public static class QosCallback.QosCallbackRegistrationException extends java.lang.RuntimeException { + } + + public final class QosCallbackException extends java.lang.Exception { + } + + public abstract class QosFilter { + method @NonNull public abstract android.net.Network getNetwork(); + method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int); + } + + public final class QosSession implements android.os.Parcelable { + ctor public QosSession(int, int); + method public int describeContents(); + method public int getSessionId(); + method public int getSessionType(); + method public long getUniqueId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR; + field public static final int TYPE_EPS_BEARER = 1; // 0x1 + } + + public interface QosSessionAttributes { + } + + public final class QosSocketInfo implements android.os.Parcelable { + ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.Socket) throws java.io.IOException; + method public int describeContents(); + method @NonNull public java.net.InetSocketAddress getLocalSocketAddress(); + method @NonNull public android.net.Network getNetwork(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR; + } + public final class RouteInfo implements android.os.Parcelable { ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int); ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int); @@ -331,6 +375,12 @@ package android.net { field public static final int SUCCESS = 0; // 0x0 } + public class SocketLocalAddressChangedException extends java.lang.Exception { + } + + public class SocketNotBoundException extends java.lang.Exception { + } + public final class StaticIpConfiguration implements android.os.Parcelable { ctor public StaticIpConfiguration(); ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration); @@ -392,16 +442,3 @@ package android.net.apf { } -package android.net.util { - - public final class SocketUtils { - method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException; - method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException; - method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int); - method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int); - method @Deprecated @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]); - method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int, @NonNull byte[]); - } - -} - diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java index e7ab0a1c7ac8..39ec2edcea3f 100644 --- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java +++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java @@ -2245,31 +2245,6 @@ public class ConnectivityManager { } } - /* TODO: These permissions checks don't belong in client-side code. Move them to - * services.jar, possibly in com.android.server.net. */ - - /** {@hide} */ - public static final void enforceChangePermission(Context context, - String callingPkg, String callingAttributionTag) { - int uid = Binder.getCallingUid(); - checkAndNoteChangeNetworkStateOperation(context, uid, callingPkg, - callingAttributionTag, true /* throwException */); - } - - /** - * Check if the package is a allowed to change the network state. This also accounts that such - * an access happened. - * - * @return {@code true} iff the package is allowed to change the network state. - */ - // TODO: Remove method and replace with direct call once R code is pushed to AOSP - private static boolean checkAndNoteChangeNetworkStateOperation(@NonNull Context context, - int uid, @NonNull String callingPackage, @Nullable String callingAttributionTag, - boolean throwException) { - return Settings.checkAndNoteChangeNetworkStateOperation(context, uid, callingPackage, - callingAttributionTag, throwException); - } - /** * Check if the package is a allowed to write settings. This also accounts that such an access * happened. diff --git a/core/java/android/net/IOnSetOemNetworkPreferenceListener.aidl b/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl index 7979afc54f90..7979afc54f90 100644 --- a/core/java/android/net/IOnSetOemNetworkPreferenceListener.aidl +++ b/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl diff --git a/core/java/android/net/IQosCallback.aidl b/packages/Connectivity/framework/src/android/net/IQosCallback.aidl index 91c75759f85c..91c75759f85c 100644 --- a/core/java/android/net/IQosCallback.aidl +++ b/packages/Connectivity/framework/src/android/net/IQosCallback.aidl diff --git a/core/java/android/net/NetworkReleasedException.java b/packages/Connectivity/framework/src/android/net/NetworkReleasedException.java index 0629b7563aea..0629b7563aea 100644 --- a/core/java/android/net/NetworkReleasedException.java +++ b/packages/Connectivity/framework/src/android/net/NetworkReleasedException.java diff --git a/packages/Connectivity/framework/src/android/net/NetworkUtils.java b/packages/Connectivity/framework/src/android/net/NetworkUtils.java index b5e8a614b8ea..9e42bbecbe9d 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkUtils.java +++ b/packages/Connectivity/framework/src/android/net/NetworkUtils.java @@ -87,22 +87,6 @@ public class NetworkUtils { public static native int bindSocketToNetwork(FileDescriptor fd, int netId); /** - * Protect {@code fd} from VPN connections. After protecting, data sent through - * this socket will go directly to the underlying network, so its traffic will not be - * forwarded through the VPN. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553, - publicAlternatives = "Use {@link android.net.VpnService#protect} instead.") - public static native boolean protectFromVpn(FileDescriptor fd); - - /** - * Protect {@code socketfd} from VPN connections. After protecting, data sent through - * this socket will go directly to the underlying network, so its traffic will not be - * forwarded through the VPN. - */ - public native static boolean protectFromVpn(int socketfd); - - /** * Determine if {@code uid} can access network designated by {@code netId}. * @return {@code true} if {@code uid} can access network, {@code false} otherwise. */ diff --git a/core/java/android/net/QosCallback.java b/packages/Connectivity/framework/src/android/net/QosCallback.java index 22f06bc0e690..22f06bc0e690 100644 --- a/core/java/android/net/QosCallback.java +++ b/packages/Connectivity/framework/src/android/net/QosCallback.java diff --git a/core/java/android/net/QosCallbackConnection.java b/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java index bdb4ad68cd7b..bdb4ad68cd7b 100644 --- a/core/java/android/net/QosCallbackConnection.java +++ b/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java diff --git a/core/java/android/net/QosCallbackException.java b/packages/Connectivity/framework/src/android/net/QosCallbackException.java index 7fd9a527e2ac..7fd9a527e2ac 100644 --- a/core/java/android/net/QosCallbackException.java +++ b/packages/Connectivity/framework/src/android/net/QosCallbackException.java diff --git a/core/java/android/net/QosFilter.java b/packages/Connectivity/framework/src/android/net/QosFilter.java index ab55002e02b3..ab55002e02b3 100644 --- a/core/java/android/net/QosFilter.java +++ b/packages/Connectivity/framework/src/android/net/QosFilter.java diff --git a/core/java/android/net/QosFilterParcelable.java b/packages/Connectivity/framework/src/android/net/QosFilterParcelable.java index da3b2cf8ff7a..da3b2cf8ff7a 100644 --- a/core/java/android/net/QosFilterParcelable.java +++ b/packages/Connectivity/framework/src/android/net/QosFilterParcelable.java diff --git a/core/java/android/net/QosSession.java b/packages/Connectivity/framework/src/android/net/QosSession.java index 4f3bb77c5877..4f3bb77c5877 100644 --- a/core/java/android/net/QosSession.java +++ b/packages/Connectivity/framework/src/android/net/QosSession.java diff --git a/core/java/android/net/QosSessionAttributes.java b/packages/Connectivity/framework/src/android/net/QosSessionAttributes.java index 7a885942d1b5..7a885942d1b5 100644 --- a/core/java/android/net/QosSessionAttributes.java +++ b/packages/Connectivity/framework/src/android/net/QosSessionAttributes.java diff --git a/core/java/android/net/QosSocketFilter.java b/packages/Connectivity/framework/src/android/net/QosSocketFilter.java index 2080e68f5fba..2080e68f5fba 100644 --- a/core/java/android/net/QosSocketFilter.java +++ b/packages/Connectivity/framework/src/android/net/QosSocketFilter.java diff --git a/core/java/android/net/QosSocketInfo.java b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java index d37c4691ddde..d37c4691ddde 100644 --- a/core/java/android/net/QosSocketInfo.java +++ b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java diff --git a/core/java/android/net/SocketLocalAddressChangedException.java b/packages/Connectivity/framework/src/android/net/SocketLocalAddressChangedException.java index 9daad83fd13e..9daad83fd13e 100644 --- a/core/java/android/net/SocketLocalAddressChangedException.java +++ b/packages/Connectivity/framework/src/android/net/SocketLocalAddressChangedException.java diff --git a/core/java/android/net/SocketNotBoundException.java b/packages/Connectivity/framework/src/android/net/SocketNotBoundException.java index b1d7026ac981..b1d7026ac981 100644 --- a/core/java/android/net/SocketNotBoundException.java +++ b/packages/Connectivity/framework/src/android/net/SocketNotBoundException.java diff --git a/core/java/android/net/UidRange.aidl b/packages/Connectivity/framework/src/android/net/UidRange.aidl index f70fc8e2fefd..f70fc8e2fefd 100644 --- a/core/java/android/net/UidRange.aidl +++ b/packages/Connectivity/framework/src/android/net/UidRange.aidl diff --git a/core/java/android/net/UidRange.java b/packages/Connectivity/framework/src/android/net/UidRange.java index f0e7da78d669..26518d32edcb 100644 --- a/core/java/android/net/UidRange.java +++ b/packages/Connectivity/framework/src/android/net/UidRange.java @@ -16,8 +16,6 @@ package android.net; -import static android.os.UserHandle.PER_USER_RANGE; - import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; @@ -52,14 +50,15 @@ public final class UidRange implements Parcelable { /** Returns the smallest user Id which is contained in this UidRange */ public int getStartUser() { - return start / PER_USER_RANGE; + return UserHandle.getUserHandleForUid(start).getIdentifier(); } /** Returns the largest user Id which is contained in this UidRange */ public int getEndUser() { - return stop / PER_USER_RANGE; + return UserHandle.getUserHandleForUid(stop).getIdentifier(); } + /** Returns whether the UidRange contains the specified UID. */ public boolean contains(int uid) { return start <= uid && uid <= stop; } @@ -72,7 +71,7 @@ public final class UidRange implements Parcelable { } /** - * @return {@code true} if this range contains every UID contained by the {@param other} range. + * @return {@code true} if this range contains every UID contained by the {@code other} range. */ public boolean containsRange(UidRange other) { return start <= other.start && other.stop <= stop; @@ -118,18 +117,18 @@ public final class UidRange implements Parcelable { } public static final @android.annotation.NonNull Creator<UidRange> CREATOR = - new Creator<UidRange>() { - @Override - public UidRange createFromParcel(Parcel in) { - int start = in.readInt(); - int stop = in.readInt(); + new Creator<UidRange>() { + @Override + public UidRange createFromParcel(Parcel in) { + int start = in.readInt(); + int stop = in.readInt(); - return new UidRange(start, stop); - } - @Override - public UidRange[] newArray(int size) { - return new UidRange[size]; - } + return new UidRange(start, stop); + } + @Override + public UidRange[] newArray(int size) { + return new UidRange[size]; + } }; /** diff --git a/packages/Connectivity/service/Android.bp b/packages/Connectivity/service/Android.bp index f20b89fb842c..e65b7b423bdc 100644 --- a/packages/Connectivity/service/Android.bp +++ b/packages/Connectivity/service/Android.bp @@ -63,6 +63,7 @@ java_library { "unsupportedappusage", ], static_libs: [ + "modules-utils-os", "net-utils-device-common", "net-utils-framework-common", "netd-client", diff --git a/packages/Connectivity/service/jarjar-rules.txt b/packages/Connectivity/service/jarjar-rules.txt index ef53ebb43c40..d8205bf780fd 100644 --- a/packages/Connectivity/service/jarjar-rules.txt +++ b/packages/Connectivity/service/jarjar-rules.txt @@ -1 +1,2 @@ -rule com.android.net.module.util.** com.android.connectivity.util.@1
\ No newline at end of file +rule com.android.net.module.util.** com.android.connectivity.net-utils.@1 +rule com.android.modules.utils.** com.android.connectivity.modules-utils.@1
\ No newline at end of file diff --git a/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java index ecd40667843e..f9584a3e15e9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java +++ b/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java @@ -38,6 +38,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.ContactsContract.DisplayPhoto; import android.provider.MediaStore; +import android.util.EventLog; import android.util.Log; import android.view.Gravity; import android.view.View; @@ -126,6 +127,14 @@ public class EditUserPhotoController { } final Uri pictureUri = data != null && data.getData() != null ? data.getData() : mTakePictureUri; + + // Check if the result is a content uri + if (!ContentResolver.SCHEME_CONTENT.equals(pictureUri.getScheme())) { + Log.e(TAG, "Invalid pictureUri scheme: " + pictureUri.getScheme()); + EventLog.writeEvent(0x534e4554, "172939189", -1, pictureUri.getPath()); + return false; + } + switch (requestCode) { case REQUEST_CODE_CROP_PHOTO: onPhotoCropped(pictureUri); diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 71e09106368b..1393116a814e 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -164,6 +164,7 @@ <uses-permission android:name="android.permission.MANAGE_APP_PREDICTIONS" /> <uses-permission android:name="android.permission.MANAGE_SEARCH_UI" /> <uses-permission android:name="android.permission.MANAGE_SMARTSPACE" /> + <uses-permission android:name="android.permission.MANAGE_UI_TRANSLATION" /> <uses-permission android:name="android.permission.NETWORK_SETTINGS" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.SET_TIME" /> diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md index 60994d892b6e..ee8d02301d5d 100644 --- a/packages/SystemUI/README.md +++ b/packages/SystemUI/README.md @@ -144,10 +144,6 @@ Biometric UI. Delegates SysUI events to WM Shell controllers. -### [com.android.systemui.people.widget.PeopleSpaceWidgetEnabler](/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetEnabler.java) - -Enables People Space widgets. - --- * [Plugins](/packages/SystemUI/docs/plugins.md) diff --git a/packages/SystemUI/docs/media-controls-pipeline.png b/packages/SystemUI/docs/media-controls-pipeline.png Binary files differnew file mode 100644 index 000000000000..e7408ad9fd4a --- /dev/null +++ b/packages/SystemUI/docs/media-controls-pipeline.png diff --git a/packages/SystemUI/docs/media-controls.md b/packages/SystemUI/docs/media-controls.md new file mode 100644 index 000000000000..579f453a3a92 --- /dev/null +++ b/packages/SystemUI/docs/media-controls.md @@ -0,0 +1,94 @@ +# SysUI Media Controls Pipeline + +[TOC] + +## Purpose + +Describe how events flow through the media controls pipeline, and provide a high level overview of what the different components do. + +## Pipeline Diagram + + + +* Orange: External inputs +* Blue: Internal listeners; all except `MediaDataManager` and `ResumeMediaBrowser` implement [`MediaDataManager.Listener`](/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt#711) and receive `onMediaDataLoaded` and `onMediaDataRemoved` events + +## Classes + +Files under [`systemui/media/`](/packages/SystemUI/src/com/android/systemui/media/): + +* UI + * `dialog/` + * Output switcher dialog (maintained by Settings team) + * IlluminationDrawable.kt + * LightSourceDrawable.kt + * These create the glow animation when you tap on a button (see [`qs_media_light_source`](/packages/SystemUI/res/drawable/qs_media_light_source.xml)). Should be reusable in other layouts. + * Carousel: + * MediaCarouselController.kt + * Keeps the carousel view up to date and handles state changes (e.g. expansion) + * Handles settings gear and page indicator + * MediaCarouselScrollHandler.kt + * Handles scrolling between players in the carousel + * MediaScrollView.kt + * Scrollview used in the carousel layout, has some custom measurement code + * Individual players: + * KeyguardMediaController.kt + * Lockscreen media controls have a special wrapper in order to work with the existing lockscreen notification layout + * MediaControlPanel.java + * Main class for media control UI + * SeekBarObserver.kt + * Updates seekbar state + * SeekBarViewModel.kt + * Implements its own `computePosition()` for the seekbar (to avoid continually polling the `PlaybackState`, which involves binder calls) + * Does some touch falsing (ignore flings, require drags to start near the thumb - otherwise users would often accidentally trigger the seekbar when they meant to move the carousel or shade) + * PlayerViewHolder.kt + * Holds references to the UI elements in the panel +* Animation support: + * MediaHierarchyManager.kt + * Responsible for placement of media view and animation between hosts + * MediaHost.kt + * Every location that a media player could be located needs a `MediaHost` + * Tracks configuration (if it should show inactive media, needs falsing, etc.) + * MediaHostStatesManager.kt + * Manages the various media host states and coordinates heights between different players + * Has the most up to date state for any location + * MediaViewController.kt + * Controls a single instance of a media player, keeps the media view states up to date +* Backend + * MediaData.kt + * Holds all the media data (track info, active/resume state, etc.) + * MediaDataCombineLatest.kt + * Combines update events from `MediaDataManager` and `MediaDeviceManager`, so that downstream listeners will have device info + * MediaDataFilter.kt + * Filters media data based on the current user + * Exit point for the pipeline: "external listeners" (currently `MediaHost` and `MediaCarouselController`), while they should be added via `MediaDataManager.addListener()`, will actually be listening to this output + * MediaDataManager.kt + * Entry point for the pipeline; initializes listener connections and assigns external listeners to the correct exit point + * Converts media notifications and resumable media info into `MediaData` + * MediaDeviceManager.kt + * Handles device updates + * MediaFeatureFlag.kt + * Utility to check whether media controls are enabled + * MediaSessionBasedFilter.kt + * Filters media events based on media session. This prevents duplicate controls in situations like casting where we might get both a local and remote object for the same media session. + * MediaTimeoutListener.kt + * Listens to `PlaybackState` and marks controls inactive after the media has been paused/stopped for 10 minutes (value can be adjusted locally with `adb shell setprop debug.sysui.media_timeout [ms]`) + * MediaResumeListener.kt + * Listens for new media data and attempts to find a valid `MediaBrowserService` for the app. If successful, sends the information back to the `MediaDataManager` + * Saves up to 5 valid `MediaBrowserService` components found this way, and queries them for recent media on boot or user change + * Note: the user can disable this feature completely (or block certain apps from being resumable) in [Settings](https://source.corp.google.com/android/packages/apps/Settings/src/com/android/settings/sound/ResumableMediaAppsController.java), in which case this listener will do nothing (or ignore updates from the blocked apps). + * ResumeMediaBrowser.java + * Connects to an app's [`MediaBrowser`](https://developer.android.com/reference/android/media/browse/MediaBrowser) to determine whether SystemUI is able to connect and find a recent [`MediaItem`](https://developer.android.com/reference/android/media/browse/MediaBrowser.MediaItem) +* Factory classes (for unit testing): + * LocalMediaManagerFactory.kt + * MediaBrowserFactory.java + * MediaControllerFactory.java + * ResumeMediaBrowserFactory.java + +## Miscellaneous + +Other useful documents: + +* [go/sysui-media-resumption-requirements](https://goto.google.com/sysui-media-resumption-requirements) - Internal documentation for app developers about how to work with media resumption +* [Playing nicely with media controls](https://android-developers.googleblog.com/2020/08/playing-nicely-with-media-controls.html) - blog post on the Android 11 updates +* [Media Controls developer guide](https://developer.android.com/guide/topics/media/media-controls) diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml index 79868093fb12..71cdaf5c7091 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml @@ -24,7 +24,7 @@ <include style="@style/BouncerSecurityContainer" layout="@layout/keyguard_host_view" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" /> </FrameLayout> diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml index 04e645bd0a32..1e142eaeef86 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml @@ -41,13 +41,14 @@ android:layout_gravity="center"> <com.android.keyguard.KeyguardSecurityViewFlipper android:id="@+id/view_flipper" - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_height="match_parent" android:clipChildren="false" android:clipToPadding="false" android:paddingTop="@dimen/keyguard_security_view_top_margin" android:paddingStart="@dimen/keyguard_security_view_lateral_margin" android:paddingEnd="@dimen/keyguard_security_view_lateral_margin" + android:layout_gravity="center" android:gravity="center"> </com.android.keyguard.KeyguardSecurityViewFlipper> </com.android.keyguard.KeyguardSecurityContainer> diff --git a/packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml b/packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml new file mode 100644 index 000000000000..e09bf7e37ed0 --- /dev/null +++ b/packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 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> + <bool name="can_use_one_handed_bouncer">true</bool> +</resources> diff --git a/packages/SystemUI/res-keyguard/values/config.xml b/packages/SystemUI/res-keyguard/values/config.xml index 8d9d6ee68c67..6176f7c1dd0a 100644 --- a/packages/SystemUI/res-keyguard/values/config.xml +++ b/packages/SystemUI/res-keyguard/values/config.xml @@ -22,4 +22,5 @@ <!-- Allow the menu hard key to be disabled in LockScreen on some devices [DO NOT TRANSLATE] --> <bool name="config_disableMenuKeyInLockScreen">false</bool> + <bool name="can_use_one_handed_bouncer">false</bool> </resources> diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml index 187ae58c2f2c..cf9de5e7e226 100644 --- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml +++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml @@ -85,10 +85,10 @@ android:tint="?attr/wallpaperTextColor" /> <ImageView - android:id="@+id/alt_left_button" + android:id="@+id/wallet_button" android:layout_height="@dimen/keyguard_affordance_height" android:layout_width="@dimen/keyguard_affordance_width" - android:layout_gravity="bottom|start" + android:layout_gravity="bottom|end" android:scaleType="center" android:tint="?attr/wallpaperTextColor" android:layout_marginStart="24dp" diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml index e2f3e2a306e3..7ba28a8483c3 100644 --- a/packages/SystemUI/res/layout/long_screenshot.xml +++ b/packages/SystemUI/res/layout/long_screenshot.xml @@ -76,7 +76,6 @@ android:layout_height="wrap_content" android:layout_marginBottom="42dp" android:layout_marginHorizontal="48dp" - android:adjustViewBounds="true" app:layout_constrainedHeight="true" app:layout_constrainedWidth="true" app:layout_constraintTop_toBottomOf="@id/guideline" @@ -110,6 +109,7 @@ android:visibility="invisible" android:layout_width="200dp" android:layout_height="200dp" + android:elevation="2dp" app:layout_constraintTop_toBottomOf="@id/guideline" app:layout_constraintLeft_toLeftOf="parent" app:handleThickness="@dimen/screenshot_crop_handle_thickness" diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 0893c1488005..761512ce3d14 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -315,7 +315,6 @@ <item>com.android.systemui.accessibility.SystemActions</item> <item>com.android.systemui.toast.ToastUI</item> <item>com.android.systemui.wmshell.WMShell</item> - <item>com.android.systemui.people.widget.PeopleSpaceWidgetEnabler</item> </string-array> <!-- QS tile shape store width. negative implies fill configuration instead of stroke--> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index 5f6fd30ffa1b..a2d7707a1569 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -29,12 +29,17 @@ import android.app.AlertDialog; import android.content.Context; import android.graphics.Insets; import android.graphics.Rect; +import android.provider.Settings; import android.util.AttributeSet; import android.util.MathUtils; import android.util.TypedValue; +import android.view.Gravity; import android.view.MotionEvent; +import android.view.OrientationEventListener; import android.view.VelocityTracker; +import android.view.View; import android.view.ViewConfiguration; +import android.view.ViewPropertyAnimator; import android.view.WindowInsets; import android.view.WindowInsetsAnimation; import android.view.WindowInsetsAnimationControlListener; @@ -55,6 +60,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import java.util.List; @@ -99,6 +105,12 @@ public class KeyguardSecurityContainer extends FrameLayout { private boolean mDisappearAnimRunning; private SwipeListener mSwipeListener; + private boolean mIsSecurityViewLeftAligned = true; + private boolean mOneHandedMode = false; + private SecurityMode mSecurityMode = SecurityMode.Invalid; + private ViewPropertyAnimator mRunningOneHandedAnimator; + private final OrientationEventListener mOrientationEventListener; + private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback = new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) { @@ -157,16 +169,20 @@ public class KeyguardSecurityContainer extends FrameLayout { // Used to notify the container when something interesting happens. public interface SecurityCallback { boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen); + void userActivity(); + void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput); /** - * @param strongAuth wheher the user has authenticated with strong authentication like - * pattern, password or PIN but not by trust agents or fingerprint + * @param strongAuth wheher the user has authenticated with strong authentication like + * pattern, password or PIN but not by trust agents or fingerprint * @param targetUserId a user that needs to be the foreground user at the finish completion. */ void finish(boolean strongAuth, int targetUserId); + void reset(); + void onCancelClicked(); } @@ -224,12 +240,136 @@ public class KeyguardSecurityContainer extends FrameLayout { super(context, attrs, defStyle); mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y); mViewConfiguration = ViewConfiguration.get(context); + + mOrientationEventListener = new OrientationEventListener(context) { + @Override + public void onOrientationChanged(int orientation) { + updateLayoutForSecurityMode(mSecurityMode); + } + }; } void onResume(SecurityMode securityMode, boolean faceAuthEnabled) { + mSecurityMode = securityMode; mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback); updateBiometricRetry(securityMode, faceAuthEnabled); + updateLayoutForSecurityMode(securityMode); + mOrientationEventListener.enable(); + } + + void updateLayoutForSecurityMode(SecurityMode securityMode) { + mSecurityMode = securityMode; + mOneHandedMode = canUseOneHandedBouncer(); + + if (mOneHandedMode) { + mIsSecurityViewLeftAligned = isOneHandedKeyguardLeftAligned(mContext); + } + + updateSecurityViewGravity(); + updateSecurityViewLocation(false); + } + + /** Return whether the one-handed keyguard should be enabled. */ + private boolean canUseOneHandedBouncer() { + // Is it enabled? + if (!getResources().getBoolean( + com.android.internal.R.bool.config_enableOneHandedKeyguard)) { + return false; + } + + if (!KeyguardSecurityModel.isSecurityViewOneHanded(mSecurityMode)) { + return false; + } + + return getResources().getBoolean(R.bool.can_use_one_handed_bouncer); + } + + /** Read whether the one-handed keyguard should be on the left/right from settings. */ + private boolean isOneHandedKeyguardLeftAligned(Context context) { + try { + return Settings.Global.getInt(context.getContentResolver(), + Settings.Global.ONE_HANDED_KEYGUARD_SIDE) + == Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT; + } catch (Settings.SettingNotFoundException ex) { + return true; + } + } + + private void updateSecurityViewGravity() { + View securityView = findKeyguardSecurityView(); + + if (securityView == null) { + return; + } + + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) securityView.getLayoutParams(); + + if (mOneHandedMode) { + lp.gravity = Gravity.LEFT | Gravity.BOTTOM; + } else { + lp.gravity = Gravity.CENTER_HORIZONTAL; + } + + securityView.setLayoutParams(lp); + } + + /** + * Moves the inner security view to the correct location (in one handed mode) with animation. + * This is triggered when the user taps on the side of the screen that is not currently occupied + * by the security view . + */ + private void updateSecurityViewLocation(boolean animate) { + View securityView = findKeyguardSecurityView(); + + if (securityView == null) { + return; + } + + if (!mOneHandedMode) { + securityView.setTranslationX(0); + return; + } + + if (mRunningOneHandedAnimator != null) { + mRunningOneHandedAnimator.cancel(); + mRunningOneHandedAnimator = null; + } + + int targetTranslation = mIsSecurityViewLeftAligned ? 0 : (int) (getMeasuredWidth() / 2f); + + if (animate) { + mRunningOneHandedAnimator = securityView.animate().translationX(targetTranslation); + mRunningOneHandedAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); + mRunningOneHandedAnimator.setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mRunningOneHandedAnimator = null; + } + }); + + mRunningOneHandedAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); + mRunningOneHandedAnimator.start(); + } else { + securityView.setTranslationX(targetTranslation); + } + } + + @Nullable + private KeyguardSecurityViewFlipper findKeyguardSecurityView() { + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + + if (isKeyguardSecurityView(child)) { + return (KeyguardSecurityViewFlipper) child; + } + } + + return null; + } + + private boolean isKeyguardSecurityView(View view) { + return view instanceof KeyguardSecurityViewFlipper; } public void onPause() { @@ -238,6 +378,7 @@ public class KeyguardSecurityContainer extends FrameLayout { mAlertDialog = null; } mSecurityViewFlipper.setWindowInsetsAnimationCallback(null); + mOrientationEventListener.disable(); } @Override @@ -319,19 +460,44 @@ public class KeyguardSecurityContainer extends FrameLayout { if (mSwipeListener != null) { mSwipeListener.onSwipeUp(); } + } else { + if (!mIsDragging) { + handleTap(event); + } } } return true; } + private void handleTap(MotionEvent event) { + // If we're using a fullscreen security mode, skip + if (!mOneHandedMode) { + return; + } + + // Did the tap hit the "other" side of the bouncer? + if ((mIsSecurityViewLeftAligned && (event.getX() > getWidth() / 2f)) + || (!mIsSecurityViewLeftAligned && (event.getX() < getWidth() / 2f))) { + mIsSecurityViewLeftAligned = !mIsSecurityViewLeftAligned; + + Settings.Global.putInt( + mContext.getContentResolver(), + Settings.Global.ONE_HANDED_KEYGUARD_SIDE, + mIsSecurityViewLeftAligned ? Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT + : Settings.Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT); + + updateSecurityViewLocation(true); + } + } + void setSwipeListener(SwipeListener swipeListener) { mSwipeListener = swipeListener; } private void startSpringAnimation(float startVelocity) { mSpringAnimation - .setStartVelocity(startVelocity) - .animateToFinalPosition(0); + .setStartVelocity(startVelocity) + .animateToFinalPosition(0); } public void startDisappearAnimation(SecurityMode securitySelection) { @@ -441,18 +607,17 @@ public class KeyguardSecurityContainer extends FrameLayout { return insets.inset(0, 0, 0, inset); } - private void showDialog(String title, String message) { if (mAlertDialog != null) { mAlertDialog.dismiss(); } mAlertDialog = new AlertDialog.Builder(mContext) - .setTitle(title) - .setMessage(message) - .setCancelable(false) - .setNeutralButton(R.string.ok, null) - .create(); + .setTitle(title) + .setMessage(message) + .setCancelable(false) + .setNeutralButton(R.string.ok, null) + .create(); if (!(mContext instanceof Activity)) { mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); } @@ -490,6 +655,47 @@ public class KeyguardSecurityContainer extends FrameLayout { } } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int maxHeight = 0; + int maxWidth = 0; + int childState = 0; + + int halfWidthMeasureSpec = MeasureSpec.makeMeasureSpec( + MeasureSpec.getSize(widthMeasureSpec) / 2, + MeasureSpec.getMode(widthMeasureSpec)); + + for (int i = 0; i < getChildCount(); i++) { + final View view = getChildAt(i); + if (view.getVisibility() != GONE) { + if (mOneHandedMode && isKeyguardSecurityView(view)) { + measureChildWithMargins(view, halfWidthMeasureSpec, 0, + heightMeasureSpec, 0); + } else { + measureChildWithMargins(view, widthMeasureSpec, 0, + heightMeasureSpec, 0); + } + final LayoutParams lp = (LayoutParams) view.getLayoutParams(); + maxWidth = Math.max(maxWidth, + view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin); + maxHeight = Math.max(maxHeight, + view.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); + childState = combineMeasuredStates(childState, view.getMeasuredState()); + } + } + + maxWidth += getPaddingLeft() + getPaddingRight(); + maxHeight += getPaddingTop() + getPaddingBottom(); + + // Check against our minimum height and width + maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); + maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); + + setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), + resolveSizeAndState(maxHeight, heightMeasureSpec, + childState << MEASURED_HEIGHT_STATE_SHIFT)); + } + void showAlmostAtWipeDialog(int attempts, int remaining, int userType) { String message = null; switch (userType) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 1a8d420fb394..fdab8db67431 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -404,6 +404,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard if (newView != null) { newView.onResume(KeyguardSecurityView.VIEW_REVEALED); mSecurityViewFlipperController.show(newView); + mView.updateLayoutForSecurityMode(securityMode); } mSecurityCallback.onSecurityModeChanged( diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java index c77c86711abf..631c24844417 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java @@ -92,4 +92,13 @@ public class KeyguardSecurityModel { throw new IllegalStateException("Unknown security quality:" + security); } } + + /** + * Returns whether the given security view should be used in a "one handed" way. This can be + * used to change how the security view is drawn (e.g. take up less of the screen, and align to + * one side). + */ + public static boolean isSecurityViewOneHanded(SecurityMode securityMode) { + return securityMode == SecurityMode.Pattern || securityMode == SecurityMode.PIN; + } } diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index fe0ae33d17f1..ae4c8e5a3327 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -59,6 +59,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.power.EnhancedEstimates; import com.android.systemui.power.PowerUI; import com.android.systemui.privacy.PrivacyItemController; +import com.android.systemui.qs.ReduceBrightColorsController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; import com.android.systemui.screenrecord.RecordingController; @@ -246,6 +247,7 @@ public class Dependency { @Inject Lazy<KeyguardUpdateMonitor> mKeyguardUpdateMonitor; @Inject Lazy<BatteryController> mBatteryController; @Inject Lazy<NightDisplayListener> mNightDisplayListener; + @Inject Lazy<ReduceBrightColorsController> mReduceBrightColorsController; @Inject Lazy<ManagedProfileController> mManagedProfileController; @Inject Lazy<NextAlarmController> mNextAlarmController; @Inject Lazy<DataSaverController> mDataSaverController; @@ -393,6 +395,8 @@ public class Dependency { mProviders.put(NightDisplayListener.class, mNightDisplayListener::get); + mProviders.put(ReduceBrightColorsController.class, mReduceBrightColorsController::get); + mProviders.put(ManagedProfileController.class, mManagedProfileController::get); mProviders.put(NextAlarmController.class, mNextAlarmController::get); diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index 865ca40b1f4c..59c0fb816a96 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -19,15 +19,18 @@ package com.android.systemui; import android.app.ActivityThread; import android.app.Application; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.os.Process; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; +import android.provider.Settings; import android.util.Log; import android.util.TimingsTraceLog; import android.view.SurfaceControl; @@ -37,6 +40,8 @@ import com.android.systemui.dagger.ContextComponentHelper; import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.dagger.SysUIComponent; import com.android.systemui.dump.DumpManager; +import com.android.systemui.people.PeopleSpaceActivity; +import com.android.systemui.people.widget.PeopleSpaceWidgetProvider; import com.android.systemui.shared.system.ThreadedRendererCompat; import com.android.systemui.util.NotificationChannels; @@ -121,6 +126,26 @@ public class SystemUIApplication extends Application implements mServices[i].onBootCompleted(); } } + // If SHOW_PEOPLE_SPACE is true, enable People Space widget provider. + // TODO(b/170396074): Migrate to new feature flag (go/silk-flags-howto) + try { + int showPeopleSpace = Settings.Global.getInt(context.getContentResolver(), + Settings.Global.SHOW_PEOPLE_SPACE, 1); + context.getPackageManager().setComponentEnabledSetting( + new ComponentName(context, PeopleSpaceWidgetProvider.class), + showPeopleSpace == 1 + ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED + : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + context.getPackageManager().setComponentEnabledSetting( + new ComponentName(context, PeopleSpaceActivity.class), + showPeopleSpace == 1 + ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED + : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + } catch (Exception e) { + Log.w(TAG, "Error enabling People Space widget:", e); + } } }, bootCompletedFilter); diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java index 726e2d06bf90..a2f96bbad203 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -25,6 +25,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.om.OverlayManager; import android.hardware.display.AmbientDisplayConfiguration; +import android.hardware.display.ColorDisplayManager; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; @@ -60,6 +61,7 @@ import com.android.systemui.navigationbar.NavigationBarOverlayController; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.PluginInitializerImpl; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.qs.ReduceBrightColorsController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; import com.android.systemui.settings.UserTracker; @@ -82,6 +84,7 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.theme.ThemeOverlayApplier; import com.android.systemui.util.leak.LeakDetector; +import com.android.systemui.util.settings.SecureSettings; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.pip.Pip; @@ -266,6 +269,15 @@ public class DependencyProvider { } /** */ + @SysUISingleton + @Provides + public ReduceBrightColorsController provideReduceBrightColorsListener( + @Background Handler bgHandler, UserTracker userTracker, + ColorDisplayManager colorDisplayManager, SecureSettings secureSettings) { + return new ReduceBrightColorsController(userTracker, bgHandler, + colorDisplayManager, secureSettings); + } + @Provides @SysUISingleton public ActivityManagerWrapper provideActivityManagerWrapper() { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java index 5d226d562c29..1ed881993800 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java @@ -27,7 +27,6 @@ import com.android.systemui.globalactions.GlobalActionsComponent; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.dagger.KeyguardModule; import com.android.systemui.media.systemsounds.HomeSoundEffectController; -import com.android.systemui.people.widget.PeopleSpaceWidgetEnabler; import com.android.systemui.power.PowerUI; import com.android.systemui.privacy.television.TvOngoingPrivacyChip; import com.android.systemui.recents.Recents; @@ -185,10 +184,4 @@ public abstract class SystemUIBinder { @IntoMap @ClassKey(HomeSoundEffectController.class) public abstract SystemUI bindHomeSoundEffectController(HomeSoundEffectController sysui); - - /** Inject into PeopleSpaceWidgetEnabler. */ - @Binds - @IntoMap - @ClassKey(PeopleSpaceWidgetEnabler.class) - public abstract SystemUI bindPeopleSpaceWidgetEnabler(PeopleSpaceWidgetEnabler sysui); } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java index 870e3bed2b7a..422ffd524aa8 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java @@ -200,7 +200,7 @@ public class NavigationModeController implements Dumpable { Log.d(TAG, " assetPaths="); ApkAssets[] assets = context.getResources().getAssets().getApkAssets(); for (ApkAssets a : assets) { - Log.d(TAG, " " + a.getAssetPath()); + Log.d(TAG, " " + a.getDebugName()); } } } diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetEnabler.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetEnabler.java deleted file mode 100644 index 3df264421d75..000000000000 --- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetEnabler.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.people.widget; - -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.PackageManager; -import android.util.Log; - -import com.android.systemui.SystemUI; -import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.people.PeopleSpaceActivity; -import com.android.systemui.statusbar.FeatureFlags; - -import javax.inject.Inject; - -/** - * Enables People Space widgets. - */ -@SysUISingleton -public class PeopleSpaceWidgetEnabler extends SystemUI { - private static final String TAG = "PeopleSpaceWdgtEnabler"; - private Context mContext; - private FeatureFlags mFeatureFlags; - - @Inject - public PeopleSpaceWidgetEnabler(Context context, FeatureFlags featureFlags) { - super(context); - mContext = context; - mFeatureFlags = featureFlags; - } - - @Override - public void start() { - Log.d(TAG, "Starting service"); - try { - boolean showPeopleSpace = mFeatureFlags.isPeopleTileEnabled(); - mContext.getPackageManager().setComponentEnabledSetting( - new ComponentName(mContext, PeopleSpaceWidgetProvider.class), - showPeopleSpace - ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED - : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP); - mContext.getPackageManager().setComponentEnabledSetting( - new ComponentName(mContext, PeopleSpaceActivity.class), - showPeopleSpace - ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED - : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP); - } catch (Exception e) { - Log.w(TAG, "Error enabling People Space widget:", e); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java b/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java new file mode 100644 index 000000000000..42d603ec5051 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs; + +import android.content.Context; +import android.database.ContentObserver; +import android.hardware.display.ColorDisplayManager; +import android.net.Uri; +import android.os.Handler; +import android.os.HandlerExecutor; +import android.provider.Settings; + +import androidx.annotation.NonNull; + +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.settings.UserTracker; +import com.android.systemui.statusbar.policy.CallbackController; +import com.android.systemui.util.settings.SecureSettings; + +import java.util.ArrayList; + +import javax.inject.Inject; + +/** + * @hide + */ +public class ReduceBrightColorsController implements + CallbackController<ReduceBrightColorsController.Listener> { + private final ColorDisplayManager mManager; + private final UserTracker mUserTracker; + private UserTracker.Callback mCurrentUserTrackerCallback; + private final Handler mHandler; + private final ContentObserver mContentObserver; + private final SecureSettings mSecureSettings; + private final ArrayList<ReduceBrightColorsController.Listener> mListeners = new ArrayList<>(); + + @Inject + public ReduceBrightColorsController(UserTracker userTracker, + @Background Handler handler, + ColorDisplayManager colorDisplayManager, + SecureSettings secureSettings) { + mManager = colorDisplayManager; + mUserTracker = userTracker; + mHandler = handler; + mSecureSettings = secureSettings; + mContentObserver = new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange, Uri uri) { + super.onChange(selfChange, uri); + final String setting = uri == null ? null : uri.getLastPathSegment(); + synchronized (mListeners) { + if (setting != null && mListeners.size() != 0) { + if (setting.equals(Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED)) { + for (Listener listener : mListeners) { + listener.onActivated(mManager.isReduceBrightColorsActivated()); + } + } + } + } + } + }; + + mCurrentUserTrackerCallback = new UserTracker.Callback() { + @Override + public void onUserChanged(int newUser, Context userContext) { + synchronized (mListeners) { + if (mListeners.size() > 0) { + mSecureSettings.unregisterContentObserver(mContentObserver); + mSecureSettings.registerContentObserverForUser( + Settings.Secure.getUriFor( + Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED), + false, mContentObserver, newUser); + } + } + } + }; + mUserTracker.addCallback(mCurrentUserTrackerCallback, new HandlerExecutor(handler)); + } + + @Override + public void addCallback(@NonNull Listener listener) { + synchronized (mListeners) { + if (!mListeners.contains(listener)) { + mListeners.add(listener); + if (mListeners.size() == 1) { + mSecureSettings.registerContentObserverForUser( + Settings.Secure.getUriFor( + Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED), + false, mContentObserver, mUserTracker.getUserId()); + } + } + } + } + + @Override + public void removeCallback(@androidx.annotation.NonNull Listener listener) { + synchronized (mListeners) { + if (mListeners.remove(listener) && mListeners.size() == 0) { + mSecureSettings.unregisterContentObserver(mContentObserver); + } + } + } + + /** Returns {@code true} if Reduce Bright Colors is activated */ + public boolean isReduceBrightColorsActivated() { + return mManager.isReduceBrightColorsActivated(); + } + + /** Sets the activation state of Reduce Bright Colors */ + public void setReduceBrightColorsActivated(boolean activated) { + mManager.setReduceBrightColorsActivated(activated); + } + + /** + * Listener invoked whenever the Reduce Bright Colors settings are changed. + */ + public interface Listener { + /** + * Listener invoked when the activated state changes. + * + * @param activated {@code true} if Reduce Bright Colors is activated. + */ + default void onActivated(boolean activated) { + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java index 33713f3724c7..d41bd7ad4d3c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java +++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java @@ -16,6 +16,8 @@ package com.android.systemui.qs.dagger; +import static com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE; + import android.content.Context; import android.hardware.display.NightDisplayListener; import android.os.Handler; @@ -25,6 +27,7 @@ import com.android.systemui.media.dagger.MediaModule; import com.android.systemui.qs.AutoAddTracker; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QSTileHost; +import com.android.systemui.qs.ReduceBrightColorsController; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.ManagedProfileController; import com.android.systemui.statusbar.policy.CastController; @@ -32,6 +35,8 @@ import com.android.systemui.statusbar.policy.DataSaverController; import com.android.systemui.statusbar.policy.HotspotController; import com.android.systemui.util.settings.SecureSettings; +import javax.inject.Named; + import dagger.Binds; import dagger.Module; import dagger.Provides; @@ -54,7 +59,9 @@ public interface QSModule { DataSaverController dataSaverController, ManagedProfileController managedProfileController, NightDisplayListener nightDisplayListener, - CastController castController) { + CastController castController, + ReduceBrightColorsController reduceBrightColorsController, + @Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable) { AutoTileManager manager = new AutoTileManager( context, autoAddTrackerBuilder, @@ -65,7 +72,9 @@ public interface QSModule { dataSaverController, managedProfileController, nightDisplayListener, - castController + castController, + reduceBrightColorsController, + isReduceBrightColorsAvailable ); manager.init(); return manager; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java index f94cabcee297..aec7b9a4b6b1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java @@ -33,46 +33,39 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; -import com.android.systemui.qs.SecureSetting; +import com.android.systemui.qs.ReduceBrightColorsController; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; -import com.android.systemui.settings.UserTracker; -import com.android.systemui.util.settings.SecureSettings; import javax.inject.Inject; import javax.inject.Named; /** Quick settings tile: Reduce Bright Colors **/ -public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> { +public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> + implements ReduceBrightColorsController.Listener{ //TODO(b/170973645): get icon drawable private final Icon mIcon = null; - private final SecureSetting mActivatedSetting; private final boolean mIsAvailable; + private final ReduceBrightColorsController mReduceBrightColorsController; + private boolean mIsListening; @Inject public ReduceBrightColorsTile( @Named(RBC_AVAILABLE) boolean isAvailable, + ReduceBrightColorsController reduceBrightColorsController, QSHost host, @Background Looper backgroundLooper, @Main Handler mainHandler, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, - QSLogger qsLogger, - UserTracker userTracker, - SecureSettings secureSettings + QSLogger qsLogger ) { super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, activityStarter, qsLogger); - - mActivatedSetting = new SecureSetting(secureSettings, mainHandler, - Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, userTracker.getUserId()) { - @Override - protected void handleValueChanged(int value, boolean observedChange) { - refreshState(); - } - }; + mReduceBrightColorsController = reduceBrightColorsController; + mReduceBrightColorsController.observe(getLifecycle(), this); mIsAvailable = isAvailable; } @@ -84,7 +77,6 @@ public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> { @Override protected void handleDestroy() { super.handleDestroy(); - mActivatedSetting.setListening(false); } @Override @@ -93,25 +85,13 @@ public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> { } @Override - public void handleSetListening(boolean listening) { - super.handleSetListening(listening); - mActivatedSetting.setListening(listening); - } - - @Override - protected void handleUserSwitch(int newUserId) { - mActivatedSetting.setUserId(newUserId); - refreshState(); - } - - @Override public Intent getLongClickIntent() { return new Intent(Settings.ACTION_REDUCE_BRIGHT_COLORS_SETTINGS); } @Override protected void handleClick() { - mActivatedSetting.setValue(mState.value ? 0 : 1); + mReduceBrightColorsController.setReduceBrightColorsActivated(!mState.value); } @Override @@ -121,7 +101,7 @@ public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> { @Override protected void handleUpdateState(BooleanState state, Object arg) { - state.value = mActivatedSetting.getValue() == 1; + state.value = mReduceBrightColorsController.isReduceBrightColorsActivated(); state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; state.label = mContext.getString(R.string.quick_settings_reduce_bright_colors_label); state.expandedAccessibilityClassName = Switch.class.getName(); @@ -132,4 +112,9 @@ public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> { public int getMetricsCategory() { return 0; } + + @Override + public void onActivated(boolean activated) { + refreshState(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java index 5b55864eed8a..c066619d049a 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java @@ -65,6 +65,9 @@ public class CropView extends View { private float mTopDelta = 0f; private float mBottomDelta = 0f; + private int mExtraTopPadding; + private int mExtraBottomPadding; + private CropBoundary mCurrentDraggingBoundary = CropBoundary.NONE; private float mStartingY; // y coordinate of ACTION_DOWN private CropInteractionListener mCropInteractionListener; @@ -117,12 +120,13 @@ public class CropView extends View { if (mCurrentDraggingBoundary != CropBoundary.NONE) { float delta = event.getY() - mStartingY; if (mCurrentDraggingBoundary == CropBoundary.TOP) { - mTopDelta = pixelsToFraction((int) MathUtils.constrain(delta, -topPx, + mTopDelta = pixelDistanceToFraction((int) MathUtils.constrain(delta, + -topPx + mExtraTopPadding, bottomPx - 2 * mCropTouchMargin - topPx)); } else { // Bottom - mBottomDelta = pixelsToFraction((int) MathUtils.constrain(delta, + mBottomDelta = pixelDistanceToFraction((int) MathUtils.constrain(delta, topPx + 2 * mCropTouchMargin - bottomPx, - getHeight() - bottomPx)); + getHeight() - bottomPx - mExtraBottomPadding)); } updateListener(event); invalidate(); @@ -195,6 +199,16 @@ public class CropView extends View { } /** + * Set additional top and bottom padding for the image being cropped (used when the + * corresponding ImageView doesn't take the full height). + */ + public void setExtraPadding(int top, int bottom) { + mExtraTopPadding = top; + mExtraBottomPadding = bottom; + invalidate(); + } + + /** * @return value [0,1] representing the position of the top crop boundary. Does not reflect * changes from any in-progress touch input. */ @@ -244,12 +258,22 @@ public class CropView extends View { true, mHandlePaint); } + /** + * Convert the given fraction position to pixel position within the View. + */ private int fractionToPixels(float frac) { - return (int) (frac * getHeight()); + return (int) (mExtraTopPadding + frac * getImageHeight()); + } + + private int getImageHeight() { + return getHeight() - mExtraTopPadding - mExtraBottomPadding; } - private float pixelsToFraction(int px) { - return px / (float) getHeight(); + /** + * Convert the given pixel distance to fraction of the image. + */ + private float pixelDistanceToFraction(int px) { + return px / (float) getImageHeight(); } private CropBoundary nearestBoundary(MotionEvent event, int topPx, int bottomPx) { diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java index 5a13ea55222d..4dc846e0e95d 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java @@ -157,6 +157,9 @@ public class LongScreenshotActivity extends Activity { }); } } + mPreview.addOnLayoutChangeListener( + (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> + updateCropLocation()); } @Override @@ -305,6 +308,27 @@ public class LongScreenshotActivity extends Activity { } } + private void updateCropLocation() { + Drawable drawable = mPreview.getDrawable(); + if (drawable == null) { + return; + } + + float imageRatio = drawable.getBounds().width() / (float) drawable.getBounds().height(); + float viewRatio = mPreview.getWidth() / (float) mPreview.getHeight(); + + if (imageRatio > viewRatio) { + // Image is full width and height is constrained, compute extra padding to inform + // CropView + float imageHeight = mPreview.getHeight() * viewRatio / imageRatio; + int extraPadding = (int) (mPreview.getHeight() - imageHeight) / 2; + mCropView.setExtraPadding(extraPadding, extraPadding); + } else { + // Image is full height + mCropView.setExtraPadding(0, 0); + } + } + private void doCapture() { mScrollCaptureController.start(mConnection, new ScrollCaptureController.ScrollCaptureCallback() { @@ -319,6 +343,7 @@ public class LongScreenshotActivity extends Activity { Log.i(TAG, "Got tiles " + imageTileSet.getWidth() + " x " + imageTileSet.getHeight()); mPreview.setImageDrawable(imageTileSet.getDrawable()); + updateCropLocation(); mMagnifierView.setDrawable(imageTileSet.getDrawable(), imageTileSet.getWidth(), imageTileSet.getHeight()); mCropView.animateBoundaryTo(CropView.CropBoundary.BOTTOM, 0.5f); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java b/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java index 7a0ec4c520b2..90f304262ea1 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java @@ -16,6 +16,8 @@ package com.android.systemui.screenshot; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.annotation.NonNull; import android.content.Context; import android.content.res.TypedArray; @@ -28,6 +30,7 @@ import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; +import android.view.ViewPropertyAnimator; import androidx.annotation.Nullable; @@ -35,7 +38,7 @@ import com.android.systemui.R; /** * MagnifierView shows a full-res cropped circular display of a given ImageTileSet, contents and - * positioning dereived from events from a CropView to which it listens. + * positioning derived from events from a CropView to which it listens. * * Not meant to be a general-purpose magnifier! */ @@ -57,6 +60,20 @@ public class MagnifierView extends View implements CropView.CropInteractionListe private float mLastCropPosition; private CropView.CropBoundary mCropBoundary; + private ViewPropertyAnimator mTranslationAnimator; + private final Animator.AnimatorListener mTranslationAnimatorListener = + new AnimatorListenerAdapter() { + @Override + public void onAnimationCancel(Animator animation) { + mTranslationAnimator = null; + } + + @Override + public void onAnimationEnd(Animator animation) { + mTranslationAnimator = null; + } + }; + public MagnifierView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } @@ -133,6 +150,8 @@ public class MagnifierView extends View implements CropView.CropInteractionListe public void onCropMotionEvent(MotionEvent event, CropView.CropBoundary boundary, float cropPosition, int cropPositionPx) { mCropBoundary = boundary; + boolean touchOnRight = event.getX() > getParentWidth() / 2; + float translateXTarget = touchOnRight ? 0 : getParentWidth() - getWidth(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastCropPosition = cropPosition; @@ -144,11 +163,22 @@ public class MagnifierView extends View implements CropView.CropInteractionListe setAlpha(0f); setTranslationX((getParentWidth() - getWidth()) / 2); setVisibility(View.VISIBLE); - boolean touchOnRight = event.getX() > getParentWidth() / 2; - float translateXTarget = touchOnRight ? 0 : getParentWidth() - getWidth(); - animate().alpha(1f).translationX(translateXTarget).scaleX(1f).scaleY(1f).start(); + mTranslationAnimator = + animate().alpha(1f).translationX(translateXTarget).scaleX(1f).scaleY(1f); + mTranslationAnimator.setListener(mTranslationAnimatorListener); + mTranslationAnimator.start(); break; case MotionEvent.ACTION_MOVE: + // The touch is near the middle if it's within 10% of the center point. + // We don't want to animate horizontally if the touch is near the middle. + boolean nearMiddle = Math.abs(event.getX() - getParentWidth() / 2) + < getParentWidth() / 10f; + boolean viewOnLeft = getTranslationX() < (getParentWidth() - getWidth()) / 2; + if (!nearMiddle && viewOnLeft != touchOnRight && mTranslationAnimator == null) { + mTranslationAnimator = animate().translationX(translateXTarget); + mTranslationAnimator.setListener(mTranslationAnimatorListener); + mTranslationAnimator.start(); + } mLastCropPosition = cropPosition; setTranslationY(cropPositionPx - getHeight() / 2); invalidate(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt index 0ad6507fb01e..dff97a679164 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.init +import android.content.Context +import android.provider.Settings import android.service.notification.StatusBarNotification import com.android.systemui.dagger.SysUISingleton import com.android.systemui.people.widget.PeopleSpaceWidgetManager @@ -58,6 +60,7 @@ import javax.inject.Inject */ @SysUISingleton class NotificationsControllerImpl @Inject constructor( + private val context: Context, private val featureFlags: FeatureFlags, private val notificationListener: NotificationListener, private val entryManager: NotificationEntryManager, @@ -129,7 +132,9 @@ class NotificationsControllerImpl @Inject constructor( entryManager.attach(notificationListener) } - if (featureFlags.isPeopleTileEnabled) { + val showPeopleSpace = Settings.Global.getInt(context.contentResolver, + Settings.Global.SHOW_PEOPLE_SPACE, 1) + if (showPeopleSpace == 1) { peopleSpaceWidgetManager.attach(notificationListener) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java index e40c262765ea..204dd9f5e58c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java @@ -14,6 +14,8 @@ package com.android.systemui.statusbar.phone; +import static com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE; + import android.content.Context; import android.content.res.Resources; import android.hardware.display.ColorDisplayManager; @@ -27,6 +29,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.qs.AutoAddTracker; import com.android.systemui.qs.QSTileHost; +import com.android.systemui.qs.ReduceBrightColorsController; import com.android.systemui.qs.SecureSetting; import com.android.systemui.qs.external.CustomTile; import com.android.systemui.statusbar.policy.CastController; @@ -41,6 +44,8 @@ import com.android.systemui.util.settings.SecureSettings; import java.util.ArrayList; import java.util.Objects; +import javax.inject.Named; + /** * Manages which tiles should be automatically added to QS. */ @@ -69,6 +74,8 @@ public class AutoTileManager implements UserAwareController { private final ManagedProfileController mManagedProfileController; private final NightDisplayListener mNightDisplayListener; private final CastController mCastController; + private final ReduceBrightColorsController mReduceBrightColorsController; + private final boolean mIsReduceBrightColorsAvailable; private final ArrayList<AutoAddSetting> mAutoAddSettingList = new ArrayList<>(); public AutoTileManager(Context context, AutoAddTracker.Builder autoAddTrackerBuilder, @@ -79,7 +86,9 @@ public class AutoTileManager implements UserAwareController { DataSaverController dataSaverController, ManagedProfileController managedProfileController, NightDisplayListener nightDisplayListener, - CastController castController) { + CastController castController, + ReduceBrightColorsController reduceBrightColorsController, + @Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable) { mContext = context; mHost = host; mSecureSettings = secureSettings; @@ -91,6 +100,8 @@ public class AutoTileManager implements UserAwareController { mManagedProfileController = managedProfileController; mNightDisplayListener = nightDisplayListener; mCastController = castController; + mReduceBrightColorsController = reduceBrightColorsController; + mIsReduceBrightColorsAvailable = isReduceBrightColorsAvailable; } /** @@ -124,9 +135,9 @@ public class AutoTileManager implements UserAwareController { if (!mAutoTracker.isAdded(CAST)) { mCastController.addCallback(mCastCallback); } - - // TODO(b/170970675): Set a listener/controller and callback for Reduce Bright Colors - // state changes. Call into ColorDisplayService to get availability/config status + if (!mAutoTracker.isAdded(BRIGHTNESS) && mIsReduceBrightColorsAvailable) { + mReduceBrightColorsController.addCallback(mReduceBrightColorsCallback); + } int settingsN = mAutoAddSettingList.size(); for (int i = 0; i < settingsN; i++) { @@ -143,6 +154,9 @@ public class AutoTileManager implements UserAwareController { if (ColorDisplayManager.isNightDisplayAvailable(mContext)) { mNightDisplayListener.setCallback(null); } + if (mIsReduceBrightColorsAvailable) { + mReduceBrightColorsController.removeCallback(mReduceBrightColorsCallback); + } mCastController.removeCallback(mCastCallback); int settingsN = mAutoAddSettingList.size(); for (int i = 0; i < settingsN; i++) { @@ -287,6 +301,24 @@ public class AutoTileManager implements UserAwareController { }; @VisibleForTesting + final ReduceBrightColorsController.Listener mReduceBrightColorsCallback = + new ReduceBrightColorsController.Listener() { + @Override + public void onActivated(boolean activated) { + if (activated) { + addReduceBrightColorsTile(); + } + } + + private void addReduceBrightColorsTile() { + if (mAutoTracker.isAdded(BRIGHTNESS)) return; + mHost.addTile(BRIGHTNESS); + mAutoTracker.setTileAdded(BRIGHTNESS); + mHandler.post(() -> mReduceBrightColorsController.removeCallback(this)); + } + }; + + @VisibleForTesting final CastController.Callback mCastCallback = new CastController.Callback() { @Override public void onCastDevicesChanged() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 986333ce5010..80109cb7a06c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.phone; import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK; import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; -import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE; import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset; import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON; import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK; @@ -74,10 +73,6 @@ import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.assist.AssistManager; -import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.controls.dagger.ControlsComponent; -import com.android.systemui.controls.ui.ControlsDialog; -import com.android.systemui.controls.ui.ControlsUiController; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.IntentButtonProvider; import com.android.systemui.plugins.IntentButtonProvider.IntentButton; @@ -130,7 +125,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private KeyguardAffordanceView mRightAffordanceView; private KeyguardAffordanceView mLeftAffordanceView; - private ImageView mAltLeftButton; + private ImageView mWalletButton; private ViewGroup mIndicationArea; private TextView mIndicationText; private TextView mIndicationTextBottom; @@ -179,11 +174,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private int mBurnInXOffset; private int mBurnInYOffset; private ActivityIntentHelper mActivityIntentHelper; - - private ControlsDialog mControlsDialog; - private ControlsComponent mControlsComponent; private int mLockScreenMode; - private BroadcastDispatcher mBroadcastDispatcher; private KeyguardUpdateMonitor mKeyguardUpdateMonitor; public KeyguardBottomAreaView(Context context) { @@ -251,7 +242,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mOverlayContainer = findViewById(R.id.overlay_container); mRightAffordanceView = findViewById(R.id.camera_button); mLeftAffordanceView = findViewById(R.id.left_button); - mAltLeftButton = findViewById(R.id.alt_left_button); + mWalletButton = findViewById(R.id.wallet_button); mIndicationArea = findViewById(R.id.keyguard_indication_area); mIndicationText = findViewById(R.id.keyguard_indication_text); mIndicationTextBottom = findViewById(R.id.keyguard_indication_text_bottom); @@ -351,10 +342,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mLeftAffordanceView.setLayoutParams(lp); updateLeftAffordanceIcon(); - lp = mAltLeftButton.getLayoutParams(); + lp = mWalletButton.getLayoutParams(); lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_width); lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_height); - mAltLeftButton.setLayoutParams(lp); + mWalletButton.setLayoutParams(lp); } private void updateRightAffordanceIcon() { @@ -427,11 +418,11 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mLeftAffordanceView.setContentDescription(state.contentDescription); } - private void updateControlsVisibility() { - if (mDozing || mControlsComponent.getVisibility() != AVAILABLE) { - mAltLeftButton.setVisibility(GONE); + private void updateWalletVisibility() { + if (mDozing) { + mWalletButton.setVisibility(GONE); } else { - mAltLeftButton.setVisibility(VISIBLE); + mWalletButton.setVisibility(VISIBLE); } } @@ -699,8 +690,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL public void startFinishDozeAnimation() { long delay = 0; - if (mAltLeftButton.getVisibility() == View.VISIBLE) { - startFinishDozeAnimationElement(mAltLeftButton, delay); + if (mWalletButton.getVisibility() == View.VISIBLE) { + startFinishDozeAnimationElement(mWalletButton, delay); } if (mLeftAffordanceView.getVisibility() == View.VISIBLE) { startFinishDozeAnimationElement(mLeftAffordanceView, delay); @@ -774,14 +765,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL updateCameraVisibility(); updateLeftAffordanceIcon(); - updateControlsVisibility(); + updateWalletVisibility(); if (dozing) { mOverlayContainer.setVisibility(INVISIBLE); - if (mControlsDialog != null) { - mControlsDialog.dismiss(); - mControlsDialog = null; - } } else { mOverlayContainer.setVisibility(VISIBLE); if (animate) { @@ -811,7 +798,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mLeftAffordanceView.setAlpha(alpha); mRightAffordanceView.setAlpha(alpha); mIndicationArea.setAlpha(alpha); - mAltLeftButton.setAlpha(alpha); + mWalletButton.setAlpha(alpha); } private class DefaultLeftButton implements IntentButton { @@ -884,38 +871,18 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL return insets; } - /** - * Show or hide controls, depending on the lock screen mode and controls - * availability. - */ - public void setupControls(ControlsComponent component, BroadcastDispatcher dispatcher) { - mControlsComponent = component; - mBroadcastDispatcher = dispatcher; - setupControls(); - } - - private void setupControls() { + private void setupWallet() { boolean inNewLayout = mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL; boolean settingEnabled = Settings.Global.getInt(mContext.getContentResolver(), "controls_lockscreen", 0) == 1; - if (!inNewLayout || !settingEnabled || !mControlsComponent.isEnabled()) { - mAltLeftButton.setVisibility(View.GONE); + if (!inNewLayout || !settingEnabled) { + mWalletButton.setVisibility(View.GONE); return; } - mControlsComponent.getControlsListingController().get() - .addCallback(list -> { - if (!list.isEmpty()) { - mAltLeftButton.setImageDrawable(list.get(0).loadIcon()); - mAltLeftButton.setOnClickListener((v) -> { - ControlsUiController ui = mControlsComponent - .getControlsUiController().get(); - mControlsDialog = new ControlsDialog(mContext, mBroadcastDispatcher) - .show(ui); - }); - } - updateControlsVisibility(); - }); + // TODO: add image + // mWalletButton.setImageDrawable(list.get(0).loadIcon()); + updateWalletVisibility(); } /** @@ -923,6 +890,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL */ public void onLockScreenModeChanged(int mode) { mLockScreenMode = mode; - setupControls(); + setupWallet(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 83c347b05012..ae14fa943a4b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -89,10 +89,8 @@ import com.android.systemui.DejankUtils; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.biometrics.AuthController; -import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.Classifier; import com.android.systemui.classifier.FalsingCollector; -import com.android.systemui.controls.dagger.ControlsComponent; import com.android.systemui.dagger.qualifiers.DisplayId; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.DozeLog; @@ -245,7 +243,6 @@ public class NotificationPanelViewController extends PanelViewController { public void onLockScreenModeChanged(int mode) { mLockScreenMode = mode; mClockPositionAlgorithm.onLockScreenModeChanged(mode); - mKeyguardBottomArea.onLockScreenModeChanged(mode); } @Override @@ -304,7 +301,6 @@ public class NotificationPanelViewController extends PanelViewController { private final QSDetailDisplayer mQSDetailDisplayer; private final FeatureFlags mFeatureFlags; private final ScrimController mScrimController; - private final ControlsComponent mControlsComponent; // Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card. // If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications @@ -520,7 +516,6 @@ public class NotificationPanelViewController extends PanelViewController { private NotificationShelfController mNotificationShelfController; private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL; - private BroadcastDispatcher mBroadcastDispatcher; private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() { @Override @@ -578,9 +573,7 @@ public class NotificationPanelViewController extends PanelViewController { UserManager userManager, MediaDataManager mediaDataManager, AmbientState ambientState, - FeatureFlags featureFlags, - ControlsComponent controlsComponent, - BroadcastDispatcher broadcastDispatcher) { + FeatureFlags featureFlags) { super(view, falsingManager, dozeLog, keyguardStateController, (SysuiStatusBarStateController) statusBarStateController, vibratorHelper, latencyTracker, flingAnimationUtilsBuilder.get(), statusBarTouchableRegionManager, @@ -623,7 +616,6 @@ public class NotificationPanelViewController extends PanelViewController { mScrimController = scrimController; mUserManager = userManager; mMediaDataManager = mediaDataManager; - mControlsComponent = controlsComponent; pulseExpansionHandler.setPulseExpandAbortListener(() -> { if (mQs != null) { mQs.animateHeaderSlidingOut(); @@ -662,7 +654,6 @@ public class NotificationPanelViewController extends PanelViewController { mEntryManager = notificationEntryManager; mConversationNotificationManager = conversationNotificationManager; mAuthController = authController; - mBroadcastDispatcher = broadcastDispatcher; mView.setBackgroundColor(Color.TRANSPARENT); OnAttachStateChangeListener onAttachStateChangeListener = new OnAttachStateChangeListener(); @@ -972,7 +963,6 @@ public class NotificationPanelViewController extends PanelViewController { mKeyguardBottomArea.setAffordanceHelper(mAffordanceHelper); mKeyguardBottomArea.setStatusBar(mStatusBar); mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete); - mKeyguardBottomArea.setupControls(mControlsComponent, mBroadcastDispatcher); } private void updateMaxDisplayedNotifications(boolean recompute) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index 55744f94f2b0..b6ed3e50ed7e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -27,7 +27,6 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; -import android.annotation.Nullable; import android.content.res.Configuration; import android.content.res.Resources; import android.os.SystemClock; @@ -1243,7 +1242,10 @@ public abstract class PanelViewController { mVelocityTracker.clear(); break; } - return false; + + // Finally, if none of the above cases applies, ensure that touches do not get handled + // by the contents of a panel that is not showing (a bit of a hack to avoid b/178277858) + return (mView.getVisibility() != View.VISIBLE); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index 6c097bdb08d3..044f52fd689e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -383,8 +383,15 @@ public class MobileSignalController extends SignalController<MobileState, Mobile int qsTypeIcon = 0; IconState qsIcon = null; CharSequence description = null; + // Mobile icon will only be shown in the statusbar in 2 scenarios + // 1. Mobile is the default network, and it is validated + // 2. Mobile is the default network, it is not validated and there is no other + // non-Carrier WiFi networks available. + boolean maybeShowIcons = (mCurrentState.inetCondition == 1) + || (mCurrentState.inetCondition == 0 + && !mNetworkController.isNonCarrierWifiNetworkAvailable()); // Only send data sim callbacks to QS. - if (mCurrentState.dataSim && mCurrentState.isDefault) { + if (mCurrentState.dataSim && mCurrentState.isDefault && maybeShowIcons) { qsTypeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.qsDataType : 0; qsIcon = new IconState(mCurrentState.enabled @@ -397,7 +404,7 @@ public class MobileSignalController extends SignalController<MobileState, Mobile boolean activityOut = mCurrentState.dataConnected && !mCurrentState.carrierNetworkChangeMode && mCurrentState.activityOut; - showDataIcon &= mCurrentState.dataSim && mCurrentState.isDefault; + showDataIcon &= mCurrentState.dataSim && mCurrentState.isDefault && maybeShowIcons; boolean showTriangle = showDataIcon && !mCurrentState.airplaneMode; int typeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.dataType : 0; showDataIcon |= mCurrentState.roaming; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 8eb1e6487046..fbdaf9cdae20 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -547,6 +547,10 @@ public class NetworkControllerImpl extends BroadcastReceiver return mWifiSignalController.isCarrierMergedWifi(subId); } + boolean isNonCarrierWifiNetworkAvailable() { + return !mNoNetworksAvailable; + } + boolean isEthernetDefault() { return mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET); } @@ -908,6 +912,11 @@ public class NetworkControllerImpl extends BroadcastReceiver return true; } + @VisibleForTesting + void setNoNetworksAvailable(boolean noNetworksAvailable) { + mNoNetworksAvailable = noNetworksAvailable; + } + private void updateAirplaneMode(boolean force) { boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) == 1); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java index 8d72c9c8810e..b9b62b415c00 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java @@ -106,10 +106,18 @@ public class WifiSignalController extends if (mCurrentState.inetCondition == 0) { contentDescription += ("," + mContext.getString(R.string.data_connection_no_internet)); } - IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription); if (mProviderModel) { + // WiFi icon will only be shown in the statusbar in 2 scenarios + // 1. WiFi is the default network, and it is validated + // 2. WiFi is the default network, it is not validated and there is no other + // non-Carrier WiFi networks available. + boolean maybeShowIcons = (mCurrentState.inetCondition == 1) + || (mCurrentState.inetCondition == 0 + && !mNetworkController.isNonCarrierWifiNetworkAvailable()); + IconState statusIcon = new IconState( + wifiVisible && maybeShowIcons, getCurrentIconId(), contentDescription); IconState qsIcon = null; - if (mCurrentState.isDefault || (!mNetworkController.isRadioOn() + if ((mCurrentState.isDefault && maybeShowIcons) || (!mNetworkController.isRadioOn() && !mNetworkController.isEthernetDefault())) { qsIcon = new IconState(mCurrentState.connected, mWifiTracker.isCaptivePortal ? R.drawable.ic_qs_wifi_disconnected @@ -123,6 +131,8 @@ public class WifiSignalController extends ); callback.setWifiIndicators(wifiIndicators); } else { + IconState statusIcon = new IconState( + wifiVisible, getCurrentIconId(), contentDescription); IconState qsIcon = new IconState(mCurrentState.connected, mWifiTracker.isCaptivePortal ? R.drawable.ic_qs_wifi_disconnected : getQsCurrentIconId(), contentDescription); @@ -146,15 +156,25 @@ public class WifiSignalController extends if (mCurrentState.inetCondition == 0) { dataContentDescription = mContext.getString(R.string.data_connection_no_internet); } - boolean qsVisible = mCurrentState.enabled - && (mCurrentState.connected && mCurrentState.inetCondition == 1); - + // Mobile icon will only be shown in the statusbar in 2 scenarios + // 1. Mobile is the default network, and it is validated + // 2. Mobile is the default network, it is not validated and there is no other + // non-Carrier WiFi networks available. + boolean maybeShowIcons = (mCurrentState.inetCondition == 1) + || (mCurrentState.inetCondition == 0 + && !mNetworkController.isNonCarrierWifiNetworkAvailable()); + boolean sbVisible = mCurrentState.enabled && mCurrentState.connected + && maybeShowIcons && mCurrentState.isDefault; IconState statusIcon = - new IconState(qsVisible, getCurrentIconIdForCarrierWifi(), contentDescription); - int qsTypeIcon = mCurrentState.connected ? icons.qsDataType : 0; - int typeIcon = mCurrentState.connected ? icons.dataType : 0; - IconState qsIcon = new IconState( - mCurrentState.connected, getQsCurrentIconIdForCarrierWifi(), contentDescription); + new IconState(sbVisible, getCurrentIconIdForCarrierWifi(), contentDescription); + int typeIcon = sbVisible ? icons.dataType : 0; + int qsTypeIcon = 0; + IconState qsIcon = null; + if (sbVisible) { + qsTypeIcon = icons.qsDataType; + qsIcon = new IconState(mCurrentState.connected, getQsCurrentIconIdForCarrierWifi(), + contentDescription); + } CharSequence description = mNetworkController.getNetworkNameForCarrierWiFi(mCurrentState.subId); MobileDataIndicators mobileDataIndicators = new MobileDataIndicators( diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java index 854be1f76722..1783fa4112b8 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java @@ -17,6 +17,7 @@ package com.android.keyguard; import static android.view.WindowInsets.Type.ime; +import static android.view.WindowInsets.Type.systemBars; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; @@ -24,13 +25,20 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.graphics.Insets; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.testing.TestableResources; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowInsets; import android.view.WindowInsetsController; +import android.widget.FrameLayout; import androidx.test.filters.SmallTest; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import org.junit.Before; @@ -45,12 +53,21 @@ import org.mockito.junit.MockitoRule; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper() public class KeyguardSecurityContainerTest extends SysuiTestCase { + private static final int SCREEN_WIDTH = 1600; + private static final int FAKE_MEASURE_SPEC = + View.MeasureSpec.makeMeasureSpec(SCREEN_WIDTH, View.MeasureSpec.EXACTLY); + + private static final SecurityMode ONE_HANDED_SECURITY_MODE = SecurityMode.PIN; + private static final SecurityMode TWO_HANDED_SECURITY_MODE = SecurityMode.Password; + + @Rule public MockitoRule mRule = MockitoJUnit.rule(); @Mock private WindowInsetsController mWindowInsetsController; + @Mock private KeyguardSecurityViewFlipper mSecurityViewFlipper; @@ -58,9 +75,18 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { @Before public void setup() { + // Needed here, otherwise when mKeyguardSecurityContainer is created below, it'll cache + // the real references (rather than the TestableResources that this call creates). + mContext.ensureTestableResources(); + FrameLayout.LayoutParams securityViewFlipperLayoutParams = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController); + when(mSecurityViewFlipper.getLayoutParams()).thenReturn(securityViewFlipperLayoutParams); mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext()); mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper; + mKeyguardSecurityContainer.addView(mSecurityViewFlipper, new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); } @Test @@ -69,4 +95,128 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { verify(mWindowInsetsController).controlWindowInsetsAnimation(eq(ime()), anyLong(), any(), any(), any()); } -}
\ No newline at end of file + + @Test + public void onMeasure_usesFullWidthWithoutOneHandedMode() { + setUpKeyguard( + /* deviceConfigCanUseOneHandedKeyguard= */false, + /* sysuiResourceCanUseOneHandedKeyguard= */ false, + ONE_HANDED_SECURITY_MODE); + + mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + + verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + } + + @Test + public void onMeasure_usesFullWidthWithDeviceFlagDisabled() { + setUpKeyguard( + /* deviceConfigCanUseOneHandedKeyguard= */false, + /* sysuiResourceCanUseOneHandedKeyguard= */ true, + ONE_HANDED_SECURITY_MODE); + + mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + } + + @Test + public void onMeasure_usesFullWidthWithSysUIFlagDisabled() { + setUpKeyguard( + /* deviceConfigCanUseOneHandedKeyguard= */true, + /* sysuiResourceCanUseOneHandedKeyguard= */ false, + ONE_HANDED_SECURITY_MODE); + + mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + } + + @Test + public void onMeasure_usesHalfWidthWithFlagsEnabled() { + setUpKeyguard( + /* deviceConfigCanUseOneHandedKeyguard= */true, + /* sysuiResourceCanUseOneHandedKeyguard= */ true, + ONE_HANDED_SECURITY_MODE); + + int halfWidthMeasureSpec = + View.MeasureSpec.makeMeasureSpec(SCREEN_WIDTH / 2, View.MeasureSpec.EXACTLY); + mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + + verify(mSecurityViewFlipper).measure(halfWidthMeasureSpec, FAKE_MEASURE_SPEC); + } + + @Test + public void onMeasure_usesFullWidthForFullScreenIme() { + setUpKeyguard( + /* deviceConfigCanUseOneHandedKeyguard= */true, + /* sysuiResourceCanUseOneHandedKeyguard= */ true, + TWO_HANDED_SECURITY_MODE); + + mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + } + + @Test + public void onMeasure_respectsViewInsets() { + int imeInsetAmount = 100; + int systemBarInsetAmount = 10; + + setUpKeyguard( + /* deviceConfigCanUseOneHandedKeyguard= */false, + /* sysuiResourceCanUseOneHandedKeyguard= */ false, + ONE_HANDED_SECURITY_MODE); + + Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount); + Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount); + + WindowInsets insets = new WindowInsets.Builder() + .setInsets(ime(), imeInset) + .setInsetsIgnoringVisibility(systemBars(), systemBarInset) + .build(); + + // It's reduced by the max of the systembar and IME, so just subtract IME inset. + int expectedHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec( + SCREEN_WIDTH - imeInsetAmount, View.MeasureSpec.EXACTLY); + + mKeyguardSecurityContainer.onApplyWindowInsets(insets); + mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, expectedHeightMeasureSpec); + } + + @Test + public void onMeasure_respectsViewInsets_largerSystembar() { + int imeInsetAmount = 0; + int systemBarInsetAmount = 10; + + setUpKeyguard( + /* deviceConfigCanUseOneHandedKeyguard= */false, + /* sysuiResourceCanUseOneHandedKeyguard= */ false, + ONE_HANDED_SECURITY_MODE); + + Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount); + Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount); + + WindowInsets insets = new WindowInsets.Builder() + .setInsets(ime(), imeInset) + .setInsetsIgnoringVisibility(systemBars(), systemBarInset) + .build(); + + int expectedHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec( + SCREEN_WIDTH - systemBarInsetAmount, View.MeasureSpec.EXACTLY); + + mKeyguardSecurityContainer.onApplyWindowInsets(insets); + mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC); + verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, expectedHeightMeasureSpec); + } + + private void setUpKeyguard( + boolean deviceConfigCanUseOneHandedKeyguard, + boolean sysuiResourceCanUseOneHandedKeyguard, + SecurityMode securityMode) { + TestableResources testableResources = mContext.getOrCreateTestableResources(); + testableResources.addOverride(com.android.internal.R.bool.config_enableOneHandedKeyguard, + deviceConfigCanUseOneHandedKeyguard); + testableResources.addOverride(R.bool.can_use_one_handed_bouncer, + sysuiResourceCanUseOneHandedKeyguard); + mKeyguardSecurityContainer.updateLayoutForSecurityMode(securityMode); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java index ffd747e09e23..880c290802df 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java @@ -18,10 +18,12 @@ package com.android.systemui.qs.tiles; import static junit.framework.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.os.Handler; -import android.provider.Settings; import android.service.quicksettings.Tile; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -34,9 +36,9 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSTileHost; +import com.android.systemui.qs.ReduceBrightColorsController; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.settings.UserTracker; -import com.android.systemui.util.settings.FakeSettings; import org.junit.Before; import org.junit.Test; @@ -60,8 +62,9 @@ public class ReduceBrightColorsTileTest extends SysuiTestCase { private QSLogger mQSLogger; @Mock private UserTracker mUserTracker; + @Mock + private ReduceBrightColorsController mReduceBrightColorsController; - private FakeSettings mFakeSettings; private TestableLooper mTestableLooper; private ReduceBrightColorsTile mTile; @@ -72,24 +75,23 @@ public class ReduceBrightColorsTileTest extends SysuiTestCase { mTestableLooper = TestableLooper.get(this); when(mHost.getContext()).thenReturn(mContext); - mFakeSettings = new FakeSettings(); mTile = new ReduceBrightColorsTile( true, + mReduceBrightColorsController, mHost, mTestableLooper.getLooper(), new Handler(mTestableLooper.getLooper()), mMetricsLogger, mStatusBarStateController, mActivityStarter, - mQSLogger, - mUserTracker, - mFakeSettings + mQSLogger ); } @Test public void testNotActive() { + when(mReduceBrightColorsController.isReduceBrightColorsActivated()).thenReturn(false); mTile.refreshState(); mTestableLooper.processAllMessages(); @@ -100,33 +102,27 @@ public class ReduceBrightColorsTileTest extends SysuiTestCase { @Test public void testActive() { - mFakeSettings.putIntForUser( - Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, - 1, - mUserTracker.getUserId()); + when(mReduceBrightColorsController.isReduceBrightColorsActivated()).thenReturn(true); mTile.refreshState(); mTestableLooper.processAllMessages(); - assertActiveState(); + assertEquals(Tile.STATE_ACTIVE, mTile.getState().state); + assertEquals(mTile.getState().label.toString(), + mContext.getString(R.string.quick_settings_reduce_bright_colors_label)); } @Test - public void testActive_clicked_isActive() { + public void testActive_clicked_featureIsActivated() { + when(mReduceBrightColorsController.isReduceBrightColorsActivated()).thenReturn(false); mTile.refreshState(); mTestableLooper.processAllMessages(); // Validity check assertEquals(Tile.STATE_INACTIVE, mTile.getState().state); mTile.handleClick(); - mTile.refreshState(); - mTestableLooper.processAllMessages(); - assertActiveState(); + verify(mReduceBrightColorsController, times(1)) + .setReduceBrightColorsActivated(eq(true)); } - private void assertActiveState() { - assertEquals(Tile.STATE_ACTIVE, mTile.getState().state); - assertEquals(mTile.getState().label.toString(), - mContext.getString(R.string.quick_settings_reduce_bright_colors_label)); - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java index 82d1f43e5e4e..094a70e24572 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.phone; +import static com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -47,6 +49,7 @@ import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.qs.AutoAddTracker; import com.android.systemui.qs.QSTileHost; +import com.android.systemui.qs.ReduceBrightColorsController; import com.android.systemui.qs.SecureSetting; import com.android.systemui.statusbar.policy.CastController; import com.android.systemui.statusbar.policy.CastController.CastDevice; @@ -67,6 +70,8 @@ import org.mockito.MockitoAnnotations; import java.util.Collections; import java.util.List; +import javax.inject.Named; + @RunWith(AndroidTestingRunner.class) @RunWithLooper @SmallTest @@ -88,9 +93,11 @@ public class AutoTileManagerTest extends SysuiTestCase { @Mock private DataSaverController mDataSaverController; @Mock private ManagedProfileController mManagedProfileController; @Mock private NightDisplayListener mNightDisplayListener; + @Mock private ReduceBrightColorsController mReduceBrightColorsController; @Mock(answer = Answers.RETURNS_SELF) private AutoAddTracker.Builder mAutoAddTrackerBuilder; @Mock private Context mUserContext; + private final boolean mIsReduceBrightColorsAvailable = true; private AutoTileManager mAutoTileManager; private SecureSettings mSecureSettings; @@ -130,7 +137,9 @@ public class AutoTileManagerTest extends SysuiTestCase { DataSaverController dataSaverController, ManagedProfileController managedProfileController, NightDisplayListener nightDisplayListener, - CastController castController) { + CastController castController, + ReduceBrightColorsController reduceBrightColorsController, + @Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable) { return new AutoTileManager(context, autoAddTrackerBuilder, mQsTileHost, Handler.createAsync(TestableLooper.get(this).getLooper()), mSecureSettings, @@ -138,13 +147,15 @@ public class AutoTileManagerTest extends SysuiTestCase { dataSaverController, managedProfileController, nightDisplayListener, - castController); + castController, + reduceBrightColorsController, + isReduceBrightColorsAvailable); } private AutoTileManager createAutoTileManager(Context context) { return createAutoTileManager(context, mAutoAddTrackerBuilder, mHotspotController, mDataSaverController, mManagedProfileController, mNightDisplayListener, - mCastController); + mCastController, mReduceBrightColorsController, mIsReduceBrightColorsAvailable); } @Test @@ -157,9 +168,11 @@ public class AutoTileManagerTest extends SysuiTestCase { ManagedProfileController mPC = mock(ManagedProfileController.class); NightDisplayListener nDS = mock(NightDisplayListener.class); CastController cC = mock(CastController.class); + ReduceBrightColorsController rBC = mock(ReduceBrightColorsController.class); AutoTileManager manager = - createAutoTileManager(mock(Context.class), builder, hC, dSC, mPC, nDS, cC); + createAutoTileManager(mock(Context.class), builder, hC, dSC, mPC, nDS, cC, rBC, + true); verify(tracker, never()).initialize(); verify(hC, never()).addCallback(any()); @@ -167,6 +180,7 @@ public class AutoTileManagerTest extends SysuiTestCase { verify(mPC, never()).addCallback(any()); verify(nDS, never()).setCallback(any()); verify(cC, never()).addCallback(any()); + verify(rBC, never()).addCallback(any()); assertNull(manager.getSecureSettingForKey(TEST_SETTING)); assertNull(manager.getSecureSettingForKey(TEST_SETTING_COMPONENT)); } @@ -207,6 +221,10 @@ public class AutoTileManagerTest extends SysuiTestCase { inOrderNightDisplay.verify(mNightDisplayListener).setCallback(isNotNull()); } + InOrder inOrderReduceBrightColors = inOrder(mReduceBrightColorsController); + inOrderReduceBrightColors.verify(mReduceBrightColorsController).removeCallback(any()); + inOrderReduceBrightColors.verify(mReduceBrightColorsController).addCallback(any()); + InOrder inOrderCast = inOrder(mCastController); inOrderCast.verify(mCastController).removeCallback(any()); inOrderCast.verify(mCastController).addCallback(any()); @@ -247,6 +265,10 @@ public class AutoTileManagerTest extends SysuiTestCase { inOrderNightDisplay.verify(mNightDisplayListener).setCallback(isNotNull()); } + InOrder inOrderReduceBrightColors = inOrder(mReduceBrightColorsController); + inOrderReduceBrightColors.verify(mReduceBrightColorsController).removeCallback(any()); + inOrderReduceBrightColors.verify(mReduceBrightColorsController).addCallback(any()); + InOrder inOrderCast = inOrder(mCastController); inOrderCast.verify(mCastController).removeCallback(any()); inOrderCast.verify(mCastController, never()).addCallback(any()); @@ -315,6 +337,18 @@ public class AutoTileManagerTest extends SysuiTestCase { verify(mQsTileHost, never()).addTile("night"); } + @Test + public void reduceBrightColorsTileAdded_whenActivated() { + mAutoTileManager.mReduceBrightColorsCallback.onActivated(true); + verify(mQsTileHost).addTile("reduce_brightness"); + } + + @Test + public void reduceBrightColorsTileNotAdded_whenDeactivated() { + mAutoTileManager.mReduceBrightColorsCallback.onActivated(false); + verify(mQsTileHost, never()).addTile("reduce_brightness"); + } + private static List<CastDevice> buildFakeCastDevice(boolean isCasting) { CastDevice cd = new CastDevice(); cd.state = isCasting ? CastDevice.STATE_CONNECTED : CastDevice.STATE_DISCONNECTED; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index dd31f522b94d..ec5114e181e8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -71,10 +71,8 @@ import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.AuthController; -import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.classifier.FalsingManagerFake; -import com.android.systemui.controls.dagger.ControlsComponent; import com.android.systemui.doze.DozeLog; import com.android.systemui.media.MediaDataManager; import com.android.systemui.media.MediaHierarchyManager; @@ -222,10 +220,6 @@ public class NotificationPanelViewTest extends SysuiTestCase { @Mock private FeatureFlags mFeatureFlags; @Mock - private ControlsComponent mControlsComponent; - @Mock - private BroadcastDispatcher mBroadcastDispatcher; - @Mock private AmbientState mAmbientState; @Mock private UserManager mUserManager; @@ -328,9 +322,7 @@ public class NotificationPanelViewTest extends SysuiTestCase { mUserManager, mMediaDataManager, mAmbientState, - mFeatureFlags, - mControlsComponent, - mBroadcastDispatcher); + mFeatureFlags); mNotificationPanelViewController.initDependencies( mStatusBar, mNotificationShelfController); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index e52b92648670..b1b71ccba8ce 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -372,6 +372,8 @@ public class NetworkControllerBaseTest extends SysuiTestCase { new NetworkCapabilities(mNetCapabilities), new LinkProperties(), false); mNetworkCallback.onCapabilitiesChanged( mock(Network.class), new NetworkCapabilities(mNetCapabilities)); + mDefaultCallbackInWifiTracker.onCapabilitiesChanged( + mock(Network.class), new NetworkCapabilities(mNetCapabilities)); } else { mNetworkCallback.onLost(mock(Network.class)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java index c6812a26c20b..847030e83115 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java @@ -223,13 +223,14 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { setWifiEnabled(true); verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK); + mNetworkController.setNoNetworksAvailable(false); setWifiStateForVcn(true, testSsid); setWifiLevelForVcn(0); - // Connected, but still not validated - does not show //verifyLastWifiIcon(false, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]); - verifyLastMobileDataIndicatorsForVcn(false, 0, TelephonyIcons.ICON_CWF, false); + verifyLastMobileDataIndicatorsForVcn(false, 0, 0, false); + mNetworkController.setNoNetworksAvailable(true); for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) { setWifiLevelForVcn(testLevel); @@ -239,7 +240,7 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { setConnectivityViaBroadcastForVcn( NetworkCapabilities.TRANSPORT_CELLULAR, false, true, mVcnTransportInfo); - verifyLastMobileDataIndicatorsForVcn(false, testLevel, TelephonyIcons.ICON_CWF, false); + verifyLastMobileDataIndicatorsForVcn(true, testLevel, TelephonyIcons.ICON_CWF, false); } } diff --git a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java index bafb641dcc9e..6828dd916701 100644 --- a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java +++ b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java @@ -40,29 +40,34 @@ public class ActionReplacingCallback extends IAccessibilityInteractionConnection private final IAccessibilityInteractionConnectionCallback mServiceCallback; private final IAccessibilityInteractionConnection mConnectionWithReplacementActions; private final int mInteractionId; + private final int mNodeWithReplacementActionsInteractionId; private final Object mLock = new Object(); @GuardedBy("mLock") - List<AccessibilityNodeInfo> mNodesWithReplacementActions; + private boolean mReplacementNodeIsReadyOrFailed; + + @GuardedBy("mLock") + AccessibilityNodeInfo mNodeWithReplacementActions; @GuardedBy("mLock") List<AccessibilityNodeInfo> mNodesFromOriginalWindow; @GuardedBy("mLock") + boolean mSetFindNodeFromOriginalWindowCalled = false; + + @GuardedBy("mLock") AccessibilityNodeInfo mNodeFromOriginalWindow; - // Keep track of whether or not we've been called back for a single node @GuardedBy("mLock") - boolean mSingleNodeCallbackHappened; + boolean mSetFindNodesFromOriginalWindowCalled = false; + - // Keep track of whether or not we've been called back for multiple node @GuardedBy("mLock") - boolean mMultiNodeCallbackHappened; + List<AccessibilityNodeInfo> mPrefetchedNodesFromOriginalWindow; - // We shouldn't get any more callbacks after we've called back the original service, but - // keep track to make sure we catch such strange things @GuardedBy("mLock") - boolean mDone; + boolean mSetPrefetchFromOriginalWindowCalled = false; + public ActionReplacingCallback(IAccessibilityInteractionConnectionCallback serviceCallback, IAccessibilityInteractionConnection connectionWithReplacementActions, @@ -70,19 +75,20 @@ public class ActionReplacingCallback extends IAccessibilityInteractionConnection mServiceCallback = serviceCallback; mConnectionWithReplacementActions = connectionWithReplacementActions; mInteractionId = interactionId; + mNodeWithReplacementActionsInteractionId = interactionId + 1; // Request the root node of the replacing window final long identityToken = Binder.clearCallingIdentity(); try { mConnectionWithReplacementActions.findAccessibilityNodeInfoByAccessibilityId( - AccessibilityNodeInfo.ROOT_NODE_ID, null, interactionId + 1, this, 0, + AccessibilityNodeInfo.ROOT_NODE_ID, null, + mNodeWithReplacementActionsInteractionId, this, 0, interrogatingPid, interrogatingTid, null, null); } catch (RemoteException re) { if (DEBUG) { Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()"); } - // Pretend we already got a (null) list of replacement nodes - mMultiNodeCallbackHappened = true; + mReplacementNodeIsReadyOrFailed = true; } finally { Binder.restoreCallingIdentity(identityToken); } @@ -90,46 +96,67 @@ public class ActionReplacingCallback extends IAccessibilityInteractionConnection @Override public void setFindAccessibilityNodeInfoResult(AccessibilityNodeInfo info, int interactionId) { - boolean readyForCallback; - synchronized(mLock) { + synchronized (mLock) { if (interactionId == mInteractionId) { mNodeFromOriginalWindow = info; + mSetFindNodeFromOriginalWindowCalled = true; + } else if (interactionId == mNodeWithReplacementActionsInteractionId) { + mNodeWithReplacementActions = info; + mReplacementNodeIsReadyOrFailed = true; } else { Slog.e(LOG_TAG, "Callback with unexpected interactionId"); return; } - - mSingleNodeCallbackHappened = true; - readyForCallback = mMultiNodeCallbackHappened; - } - if (readyForCallback) { - replaceInfoActionsAndCallService(); } + replaceInfoActionsAndCallServiceIfReady(); } @Override public void setFindAccessibilityNodeInfosResult(List<AccessibilityNodeInfo> infos, int interactionId) { - boolean callbackForSingleNode; - boolean callbackForMultipleNodes; - synchronized(mLock) { + synchronized (mLock) { if (interactionId == mInteractionId) { mNodesFromOriginalWindow = infos; - } else if (interactionId == mInteractionId + 1) { - mNodesWithReplacementActions = infos; + mSetFindNodesFromOriginalWindowCalled = true; + } else if (interactionId == mNodeWithReplacementActionsInteractionId) { + setNodeWithReplacementActionsFromList(infos); + mReplacementNodeIsReadyOrFailed = true; } else { Slog.e(LOG_TAG, "Callback with unexpected interactionId"); return; } - callbackForSingleNode = mSingleNodeCallbackHappened; - callbackForMultipleNodes = mMultiNodeCallbackHappened; - mMultiNodeCallbackHappened = true; } - if (callbackForSingleNode) { - replaceInfoActionsAndCallService(); + replaceInfoActionsAndCallServiceIfReady(); + } + + @Override + public void setPrefetchAccessibilityNodeInfoResult(List<AccessibilityNodeInfo> infos, + int interactionId) + throws RemoteException { + synchronized (mLock) { + if (interactionId == mInteractionId) { + mPrefetchedNodesFromOriginalWindow = infos; + mSetPrefetchFromOriginalWindowCalled = true; + } else { + Slog.e(LOG_TAG, "Callback with unexpected interactionId"); + return; + } } - if (callbackForMultipleNodes) { - replaceInfosActionsAndCallService(); + replaceInfoActionsAndCallServiceIfReady(); + } + + private void replaceInfoActionsAndCallServiceIfReady() { + replaceInfoActionsAndCallService(); + replaceInfosActionsAndCallService(); + replacePrefetchInfosActionsAndCallService(); + } + + private void setNodeWithReplacementActionsFromList(List<AccessibilityNodeInfo> infos) { + for (int i = 0; i < infos.size(); i++) { + AccessibilityNodeInfo info = infos.get(i); + if (info.getSourceNodeId() == AccessibilityNodeInfo.ROOT_NODE_ID) { + mNodeWithReplacementActions = info; + } } } @@ -142,55 +169,81 @@ public class ActionReplacingCallback extends IAccessibilityInteractionConnection private void replaceInfoActionsAndCallService() { final AccessibilityNodeInfo nodeToReturn; + boolean doCallback = false; synchronized (mLock) { - if (mDone) { - if (DEBUG) { - Slog.e(LOG_TAG, "Extra callback"); - } - return; - } - if (mNodeFromOriginalWindow != null) { + doCallback = mReplacementNodeIsReadyOrFailed + && mSetFindNodeFromOriginalWindowCalled; + if (doCallback && mNodeFromOriginalWindow != null) { replaceActionsOnInfoLocked(mNodeFromOriginalWindow); + mSetFindNodeFromOriginalWindowCalled = false; } - recycleReplaceActionNodesLocked(); nodeToReturn = mNodeFromOriginalWindow; - mDone = true; } - try { - mServiceCallback.setFindAccessibilityNodeInfoResult(nodeToReturn, mInteractionId); - } catch (RemoteException re) { - if (DEBUG) { - Slog.e(LOG_TAG, "Failed to setFindAccessibilityNodeInfoResult"); + if (doCallback) { + try { + mServiceCallback.setFindAccessibilityNodeInfoResult(nodeToReturn, mInteractionId); + } catch (RemoteException re) { + if (DEBUG) { + Slog.e(LOG_TAG, "Failed to setFindAccessibilityNodeInfoResult"); + } } } } private void replaceInfosActionsAndCallService() { - final List<AccessibilityNodeInfo> nodesToReturn; + List<AccessibilityNodeInfo> nodesToReturn = null; + boolean doCallback = false; synchronized (mLock) { - if (mDone) { + doCallback = mReplacementNodeIsReadyOrFailed + && mSetFindNodesFromOriginalWindowCalled; + if (doCallback) { + nodesToReturn = replaceActionsLocked(mNodesFromOriginalWindow); + mSetFindNodesFromOriginalWindowCalled = false; + } + } + if (doCallback) { + try { + mServiceCallback.setFindAccessibilityNodeInfosResult(nodesToReturn, mInteractionId); + } catch (RemoteException re) { if (DEBUG) { - Slog.e(LOG_TAG, "Extra callback"); + Slog.e(LOG_TAG, "Failed to setFindAccessibilityNodeInfosResult"); } - return; } - if (mNodesFromOriginalWindow != null) { - for (int i = 0; i < mNodesFromOriginalWindow.size(); i++) { - replaceActionsOnInfoLocked(mNodesFromOriginalWindow.get(i)); + } + } + + private void replacePrefetchInfosActionsAndCallService() { + List<AccessibilityNodeInfo> nodesToReturn = null; + boolean doCallback = false; + synchronized (mLock) { + doCallback = mReplacementNodeIsReadyOrFailed + && mSetPrefetchFromOriginalWindowCalled; + if (doCallback) { + nodesToReturn = replaceActionsLocked(mPrefetchedNodesFromOriginalWindow); + mSetPrefetchFromOriginalWindowCalled = false; + } + } + if (doCallback) { + try { + mServiceCallback.setPrefetchAccessibilityNodeInfoResult( + nodesToReturn, mInteractionId); + } catch (RemoteException re) { + if (DEBUG) { + Slog.e(LOG_TAG, "Failed to setFindAccessibilityNodeInfosResult"); } } - recycleReplaceActionNodesLocked(); - nodesToReturn = (mNodesFromOriginalWindow == null) - ? null : new ArrayList<>(mNodesFromOriginalWindow); - mDone = true; } - try { - mServiceCallback.setFindAccessibilityNodeInfosResult(nodesToReturn, mInteractionId); - } catch (RemoteException re) { - if (DEBUG) { - Slog.e(LOG_TAG, "Failed to setFindAccessibilityNodeInfosResult"); + } + + @GuardedBy("mLock") + private List<AccessibilityNodeInfo> replaceActionsLocked(List<AccessibilityNodeInfo> infos) { + if (infos != null) { + for (int i = 0; i < infos.size(); i++) { + replaceActionsOnInfoLocked(infos.get(i)); } } + return (infos == null) + ? null : new ArrayList<>(infos); } @GuardedBy("mLock") @@ -204,40 +257,22 @@ public class ActionReplacingCallback extends IAccessibilityInteractionConnection info.setDismissable(false); // We currently only replace actions for the root node if ((info.getSourceNodeId() == AccessibilityNodeInfo.ROOT_NODE_ID) - && mNodesWithReplacementActions != null) { - // This list should always contain a single node with the root ID - for (int i = 0; i < mNodesWithReplacementActions.size(); i++) { - AccessibilityNodeInfo nodeWithReplacementActions = - mNodesWithReplacementActions.get(i); - if (nodeWithReplacementActions.getSourceNodeId() - == AccessibilityNodeInfo.ROOT_NODE_ID) { - List<AccessibilityAction> actions = nodeWithReplacementActions.getActionList(); - if (actions != null) { - for (int j = 0; j < actions.size(); j++) { - info.addAction(actions.get(j)); - } - // The PIP needs to be able to take accessibility focus - info.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS); - info.addAction(AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS); - } - info.setClickable(nodeWithReplacementActions.isClickable()); - info.setFocusable(nodeWithReplacementActions.isFocusable()); - info.setContextClickable(nodeWithReplacementActions.isContextClickable()); - info.setScrollable(nodeWithReplacementActions.isScrollable()); - info.setLongClickable(nodeWithReplacementActions.isLongClickable()); - info.setDismissable(nodeWithReplacementActions.isDismissable()); + && mNodeWithReplacementActions != null) { + List<AccessibilityAction> actions = mNodeWithReplacementActions.getActionList(); + if (actions != null) { + for (int j = 0; j < actions.size(); j++) { + info.addAction(actions.get(j)); } + // The PIP needs to be able to take accessibility focus + info.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS); + info.addAction(AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS); } + info.setClickable(mNodeWithReplacementActions.isClickable()); + info.setFocusable(mNodeWithReplacementActions.isFocusable()); + info.setContextClickable(mNodeWithReplacementActions.isContextClickable()); + info.setScrollable(mNodeWithReplacementActions.isScrollable()); + info.setLongClickable(mNodeWithReplacementActions.isLongClickable()); + info.setDismissable(mNodeWithReplacementActions.isDismissable()); } } - - @GuardedBy("mLock") - private void recycleReplaceActionNodesLocked() { - if (mNodesWithReplacementActions == null) return; - for (int i = mNodesWithReplacementActions.size() - 1; i >= 0; i--) { - AccessibilityNodeInfo nodeWithReplacementAction = mNodesWithReplacementActions.get(i); - nodeWithReplacementAction.recycle(); - } - mNodesWithReplacementActions = null; - } } diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 50ad6617b1fe..e251700498ee 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -19,6 +19,7 @@ package com.android.server.appwidget; import static android.content.Context.KEYGUARD_SERVICE; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.content.res.Resources.ID_NULL; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; @@ -2578,9 +2579,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku info.updatePeriodMillis = sa.getInt( com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0); info.initialLayout = sa.getResourceId( - com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0); + com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, ID_NULL); info.initialKeyguardLayout = sa.getResourceId(com.android.internal.R.styleable. - AppWidgetProviderInfo_initialKeyguardLayout, 0); + AppWidgetProviderInfo_initialKeyguardLayout, ID_NULL); String className = sa .getString(com.android.internal.R.styleable.AppWidgetProviderInfo_configure); @@ -2591,11 +2592,12 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku info.label = activityInfo.loadLabel(pm).toString(); info.icon = activityInfo.getIconResource(); info.previewImage = sa.getResourceId( - com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0); + com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, ID_NULL); info.previewLayout = sa.getResourceId( - com.android.internal.R.styleable.AppWidgetProviderInfo_previewLayout, 0); + com.android.internal.R.styleable.AppWidgetProviderInfo_previewLayout, ID_NULL); info.autoAdvanceViewId = sa.getResourceId( - com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1); + com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, + View.NO_ID); info.resizeMode = sa.getInt( com.android.internal.R.styleable.AppWidgetProviderInfo_resizeMode, AppWidgetProviderInfo.RESIZE_NONE); @@ -2605,8 +2607,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku info.widgetFeatures = sa.getInt( com.android.internal.R.styleable.AppWidgetProviderInfo_widgetFeatures, 0); info.descriptionRes = sa.getResourceId( - com.android.internal.R.styleable.AppWidgetProviderInfo_description, - Resources.ID_NULL); + com.android.internal.R.styleable.AppWidgetProviderInfo_description, ID_NULL); sa.recycle(); return info; } catch (IOException | PackageManager.NameNotFoundException | XmlPullParserException e) { diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 542d527177a1..ff3d0162a2f8 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -120,6 +120,7 @@ import android.net.NetworkSpecifier; import android.net.NetworkStack; import android.net.NetworkStackClient; import android.net.NetworkState; +import android.net.NetworkStateSnapshot; import android.net.NetworkTestResultParcelable; import android.net.NetworkUtils; import android.net.NetworkWatchlistManager; @@ -155,7 +156,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; -import android.os.INetworkManagementService; import android.os.Looper; import android.os.Message; import android.os.Messenger; @@ -324,7 +324,6 @@ public class ConnectivityService extends IConnectivityManager.Stub // 0 is full bad, 100 is full good private int mDefaultInetConditionPublished = 0; - private INetworkManagementService mNMS; @VisibleForTesting protected IDnsResolver mDnsResolver; @VisibleForTesting @@ -1040,15 +1039,14 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - public ConnectivityService(Context context, INetworkManagementService netManager, - INetworkStatsService statsService) { - this(context, netManager, statsService, getDnsResolver(context), new IpConnectivityLog(), + public ConnectivityService(Context context, INetworkStatsService statsService) { + this(context, statsService, getDnsResolver(context), new IpConnectivityLog(), NetdService.getInstance(), new Dependencies()); } @VisibleForTesting - protected ConnectivityService(Context context, INetworkManagementService netManager, - INetworkStatsService statsService, IDnsResolver dnsresolver, IpConnectivityLog logger, + protected ConnectivityService(Context context, INetworkStatsService statsService, + IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd, Dependencies deps) { if (DBG) log("ConnectivityService starting up"); @@ -1095,7 +1093,6 @@ public class ConnectivityService extends IConnectivityManager.Stub // TODO: Consider making the timer customizable. mNascentDelayMs = DEFAULT_NASCENT_DELAY_MS; - mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService"); mStatsService = Objects.requireNonNull(statsService, "missing INetworkStatsService"); mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class); mPolicyManagerInternal = Objects.requireNonNull( @@ -1203,7 +1200,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mUserAllContext.registerReceiver(mIntentReceiver, intentFilter, null /* broadcastPermission */, mHandler); - mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNMS, mNetd); + mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNetd); mNetdCallback = new NetdCallback(); try { @@ -1237,12 +1234,12 @@ public class ConnectivityService extends IConnectivityManager.Stub mDnsManager = new DnsManager(mContext, mDnsResolver); registerPrivateDnsSettingsCallbacks(); - mNoServiceNetwork = new NetworkAgentInfo(null, + mNoServiceNetwork = new NetworkAgentInfo(null, new Network(NO_SERVICE_NET_ID), new NetworkInfo(TYPE_NONE, 0, "", ""), new LinkProperties(), new NetworkCapabilities(), 0, mContext, null, new NetworkAgentConfig(), this, null, - null, null, 0, INVALID_UID, + null, 0, INVALID_UID, mQosCallbackTracker); } @@ -2201,8 +2198,45 @@ public class ConnectivityService extends IConnectivityManager.Stub "ConnectivityService"); } + /** + * Performs a strict and comprehensive check of whether a calling package is allowed to + * change the state of network, as the condition differs for pre-M, M+, and + * privileged/preinstalled apps. The caller is expected to have either the + * CHANGE_NETWORK_STATE or the WRITE_SETTINGS permission declared. Either of these + * permissions allow changing network state; WRITE_SETTINGS is a runtime permission and + * can be revoked, but (except in M, excluding M MRs), CHANGE_NETWORK_STATE is a normal + * permission and cannot be revoked. See http://b/23597341 + * + * Note: if the check succeeds because the application holds WRITE_SETTINGS, the operation + * of this app will be updated to the current time. + */ private void enforceChangePermission(String callingPkg, String callingAttributionTag) { - ConnectivityManager.enforceChangePermission(mContext, callingPkg, callingAttributionTag); + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE) + == PackageManager.PERMISSION_GRANTED) { + return; + } + + if (callingPkg == null) { + throw new SecurityException("Calling package name is null."); + } + + final AppOpsManager appOpsMgr = mContext.getSystemService(AppOpsManager.class); + final int uid = mDeps.getCallingUid(); + final int mode = appOpsMgr.noteOpNoThrow(AppOpsManager.OPSTR_WRITE_SETTINGS, uid, + callingPkg, callingAttributionTag, null /* message */); + + if (mode == AppOpsManager.MODE_ALLOWED) { + return; + } + + if ((mode == AppOpsManager.MODE_DEFAULT) && (mContext.checkCallingOrSelfPermission( + android.Manifest.permission.WRITE_SETTINGS) == PackageManager.PERMISSION_GRANTED)) { + return; + } + + throw new SecurityException(callingPkg + " was not granted either of these permissions:" + + android.Manifest.permission.CHANGE_NETWORK_STATE + "," + + android.Manifest.permission.WRITE_SETTINGS + "."); } private void enforceSettingsPermission() { @@ -6030,7 +6064,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkAgentInfo nai = new NetworkAgentInfo(na, new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig), - this, mNetd, mDnsResolver, mNMS, providerId, uid, mQosCallbackTracker); + this, mNetd, mDnsResolver, providerId, uid, mQosCallbackTracker); // Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says. processCapabilitiesFromAgent(nai, nc); @@ -7952,8 +7986,16 @@ public class ConnectivityService extends IConnectivityManager.Stub final UnderlyingNetworkInfo[] underlyingNetworkInfos = getAllVpnInfo(); try { - mStatsService.forceUpdateIfaces(getDefaultNetworks(), getAllNetworkState(), activeIface, - underlyingNetworkInfos); + final ArrayList<NetworkStateSnapshot> snapshots = new ArrayList<>(); + // TODO: Directly use NetworkStateSnapshot when feasible. + for (final NetworkState state : getAllNetworkState()) { + final NetworkStateSnapshot snapshot = new NetworkStateSnapshot(state.network, + state.networkCapabilities, state.linkProperties, state.subscriberId, + state.legacyNetworkType); + snapshots.add(snapshot); + } + mStatsService.forceUpdateIfaces(getDefaultNetworks(), snapshots.toArray( + new NetworkStateSnapshot[0]), activeIface, underlyingNetworkInfos); } catch (Exception ignored) { } } @@ -8186,7 +8228,7 @@ public class ConnectivityService extends IConnectivityManager.Stub TestNetworkService.enforceTestNetworkPermissions(mContext); if (mTNS == null) { - mTNS = new TestNetworkService(mContext, mNMS); + mTNS = new TestNetworkService(mContext); } return mTNS; @@ -8661,9 +8703,23 @@ public class ConnectivityService extends IConnectivityManager.Stub private class NetdCallback extends BaseNetdUnsolicitedEventListener { @Override - public void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, + public void onInterfaceClassActivityChanged(boolean isActive, int transportType, long timestampNs, int uid) { - mNetworkActivityTracker.setAndReportNetworkActive(isActive, timerLabel, timestampNs); + mNetworkActivityTracker.setAndReportNetworkActive(isActive, transportType, timestampNs); + } + + @Override + public void onInterfaceLinkStateChanged(String iface, boolean up) { + for (NetworkAgentInfo nai : mNetworkAgentInfos) { + nai.clatd.interfaceLinkStateChanged(iface, up); + } + } + + @Override + public void onInterfaceRemoved(String iface) { + for (NetworkAgentInfo nai : mNetworkAgentInfos) { + nai.clatd.interfaceRemoved(iface); + } } } @@ -8697,7 +8753,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } LegacyNetworkActivityTracker(@NonNull Context context, @NonNull Handler handler, - @NonNull INetworkManagementService nms, @NonNull INetd netd) { + @NonNull INetd netd) { mContext = context; mNetd = netd; mHandler = handler; diff --git a/services/core/java/com/android/server/ConnectivityServiceInitializer.java b/services/core/java/com/android/server/ConnectivityServiceInitializer.java index 0779f7117d82..097441f706e6 100644 --- a/services/core/java/com/android/server/ConnectivityServiceInitializer.java +++ b/services/core/java/com/android/server/ConnectivityServiceInitializer.java @@ -21,7 +21,6 @@ import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; import android.content.Context; import android.net.INetworkStatsService; -import android.os.INetworkManagementService; import android.os.ServiceManager; import android.util.Log; @@ -38,8 +37,7 @@ public final class ConnectivityServiceInitializer extends SystemService { // Load JNI libraries used by ConnectivityService and its dependencies System.loadLibrary("service-connectivity"); // TODO: Define formal APIs to get the needed services. - mConnectivity = new ConnectivityService(context, getNetworkManagementService(), - getNetworkStatsService()); + mConnectivity = new ConnectivityService(context, getNetworkStatsService()); } @Override @@ -49,11 +47,6 @@ public final class ConnectivityServiceInitializer extends SystemService { /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL); } - private INetworkManagementService getNetworkManagementService() { - return INetworkManagementService.Stub.asInterface( - ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)); - } - private INetworkStatsService getNetworkStatsService() { return INetworkStatsService.Stub.asInterface( ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 44054088d937..10d6570929ed 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -44,7 +44,6 @@ import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENAB import android.annotation.NonNull; import android.app.ActivityManager; import android.content.Context; -import android.net.ConnectivityManager; import android.net.INetd; import android.net.INetdUnsolicitedEventListener; import android.net.INetworkManagementEventObserver; @@ -54,7 +53,6 @@ import android.net.InterfaceConfiguration; import android.net.InterfaceConfigurationParcel; import android.net.IpPrefix; import android.net.LinkAddress; -import android.net.Network; import android.net.NetworkPolicyManager; import android.net.NetworkStack; import android.net.NetworkStats; @@ -974,19 +972,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub { } @Override - public void setDnsForwarders(Network network, String[] dns) { - NetworkStack.checkNetworkStackPermission(mContext); - - int netId = (network != null) ? network.netId : ConnectivityManager.NETID_UNSET; - - try { - mNetdService.tetherDnsSet(netId, dns); - } catch (RemoteException | ServiceSpecificException e) { - throw new IllegalStateException(e); - } - } - - @Override public String[] getDnsForwarders() { NetworkStack.checkNetworkStackPermission(mContext); try { @@ -1775,27 +1760,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub { } @Override - public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) { - NetworkStack.checkNetworkStackPermission(mContext); - - final LinkAddress la = routeInfo.getDestinationLinkAddress(); - final String ifName = routeInfo.getInterface(); - final String dst = la.toString(); - final String nextHop; - - if (routeInfo.hasGateway()) { - nextHop = routeInfo.getGateway().getHostAddress(); - } else { - nextHop = ""; - } - try { - mNetdService.networkAddLegacyRoute(netId, ifName, dst, nextHop, uid); - } catch (RemoteException | ServiceSpecificException e) { - throw new IllegalStateException(e); - } - } - - @Override public void allowProtect(int uid) { NetworkStack.checkNetworkStackPermission(mContext); diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java index 96f832d26816..55408ea61566 100644 --- a/services/core/java/com/android/server/TestNetworkService.java +++ b/services/core/java/com/android/server/TestNetworkService.java @@ -32,7 +32,6 @@ import android.net.NetworkAgent; import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkProvider; -import android.net.NetworkStack; import android.net.RouteInfo; import android.net.StringNetworkSpecifier; import android.net.TestNetworkInterface; @@ -41,7 +40,6 @@ import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; -import android.os.INetworkManagementService; import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -51,6 +49,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.NetdUtils; import com.android.net.module.util.NetworkStackConstants; +import com.android.net.module.util.PermissionUtils; import java.io.UncheckedIOException; import java.net.Inet4Address; @@ -69,7 +68,6 @@ class TestNetworkService extends ITestNetworkManager.Stub { @NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger(); @NonNull private final Context mContext; - @NonNull private final INetworkManagementService mNMS; @NonNull private final INetd mNetd; @NonNull private final HandlerThread mHandlerThread; @@ -82,14 +80,12 @@ class TestNetworkService extends ITestNetworkManager.Stub { private static native int jniCreateTunTap(boolean isTun, @NonNull String iface); @VisibleForTesting - protected TestNetworkService( - @NonNull Context context, @NonNull INetworkManagementService netManager) { + protected TestNetworkService(@NonNull Context context) { mHandlerThread = new HandlerThread("TestNetworkServiceThread"); mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper()); mContext = Objects.requireNonNull(context, "missing Context"); - mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService"); mNetd = Objects.requireNonNull(NetdService.getInstance(), "could not get netd instance"); mCm = mContext.getSystemService(ConnectivityManager.class); mNetworkProvider = new NetworkProvider(mContext, mHandler.getLooper(), @@ -324,7 +320,7 @@ class TestNetworkService extends ITestNetworkManager.Stub { try { final long token = Binder.clearCallingIdentity(); try { - NetworkStack.checkNetworkStackPermission(mContext); + PermissionUtils.enforceNetworkStackPermission(mContext); NetdUtils.setInterfaceUp(mNetd, iface); } finally { Binder.restoreCallingIdentity(token); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 7cd494976c94..e8a4fa20cd30 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -15179,8 +15179,8 @@ public class ActivityManagerService extends IActivityManager.Stub mFgsStartTempAllowList.add(changingUid, durationMs, reasonCode, reason, callingUid); } - setAppIdTempAllowlistStateLSP(changingUid, adding); } + setAppIdTempAllowlistStateLSP(changingUid, adding); } } } diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index 2de709ebe71d..42fcd4460386 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -880,8 +880,8 @@ public class ClipboardService extends SystemService { CharSequence sourceAppLabel = null; if (clipboard.mPrimaryClipPackage != null) { try { - sourceAppLabel = mPm.getApplicationLabel( - mPm.getApplicationInfo(clipboard.mPrimaryClipPackage, 0)); + sourceAppLabel = mPm.getApplicationLabel(mPm.getApplicationInfoAsUser( + clipboard.mPrimaryClipPackage, 0, userId)); } catch (PackageManager.NameNotFoundException e) { // leave label as null } @@ -889,7 +889,7 @@ public class ClipboardService extends SystemService { try { CharSequence callingAppLabel = mPm.getApplicationLabel( - mPm.getApplicationInfo(callingPackage, 0)); + mPm.getApplicationInfoAsUser(callingPackage, 0, userId)); String message; if (sourceAppLabel != null) { message = callingAppLabel + " pasted from " + sourceAppLabel; diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java index df83df9a73fb..5cf478a3ef1f 100644 --- a/services/core/java/com/android/server/compat/CompatChange.java +++ b/services/core/java/com/android/server/compat/CompatChange.java @@ -80,6 +80,15 @@ public final class CompatChange extends CompatibilityChangeInfo { } /** + * @param change an object generated by services/core/xsd/platform-compat-config.xsd + */ + public CompatChange(Change change) { + this(change.getId(), change.getName(), change.getEnableAfterTargetSdk(), + change.getEnableSinceTargetSdk(), change.getDisabled(), change.getLoggingOnly(), + change.getDescription(), change.getOverridable()); + } + + /** * @param changeId Unique ID for the change. See {@link android.compat.Compatibility}. * @param name Short descriptive name. * @param enableAfterTargetSdk {@code targetSdkVersion} restriction. See {@link EnabledAfter}; @@ -93,15 +102,10 @@ public final class CompatChange extends CompatibilityChangeInfo { boolean overridable) { super(changeId, name, enableAfterTargetSdk, enableSinceTargetSdk, disabled, loggingOnly, description, overridable); - } - /** - * @param change an object generated by services/core/xsd/platform-compat-config.xsd - */ - public CompatChange(Change change) { - super(change.getId(), change.getName(), change.getEnableAfterTargetSdk(), - change.getEnableSinceTargetSdk(), change.getDisabled(), change.getLoggingOnly(), - change.getDescription(), change.getOverridable()); + // Initialize override maps. + mEvaluatedOverrides = new HashMap<>(); + mRawOverrides = new HashMap<>(); } void registerListener(ChangeListener listener) { @@ -127,18 +131,13 @@ public final class CompatChange extends CompatibilityChangeInfo { throw new IllegalArgumentException( "Can't add overrides for a logging only change " + toString()); } - if (mEvaluatedOverrides == null) { - mEvaluatedOverrides = new HashMap<>(); - } mEvaluatedOverrides.put(pname, enabled); notifyListener(pname); } private void removePackageOverrideInternal(String pname) { - if (mEvaluatedOverrides != null) { - if (mEvaluatedOverrides.remove(pname) != null) { - notifyListener(pname); - } + if (mEvaluatedOverrides.remove(pname) != null) { + notifyListener(pname); } } @@ -157,9 +156,6 @@ public final class CompatChange extends CompatibilityChangeInfo { throw new IllegalArgumentException( "Can't add overrides for a logging only change " + toString()); } - if (mRawOverrides == null) { - mRawOverrides = new HashMap<>(); - } mRawOverrides.put(packageName, override); recheckOverride(packageName, allowedState, context); } @@ -212,7 +208,7 @@ public final class CompatChange extends CompatibilityChangeInfo { } boolean hasPackageOverride(String pname) { - return mRawOverrides != null && mRawOverrides.containsKey(pname); + return mRawOverrides.containsKey(pname); } /** * Remove any package override for the given package name, restoring the default behaviour. @@ -223,7 +219,7 @@ public final class CompatChange extends CompatibilityChangeInfo { */ boolean removePackageOverride(String pname, OverrideAllowedState allowedState, Context context) { - if (mRawOverrides != null && (mRawOverrides.remove(pname) != null)) { + if (mRawOverrides.remove(pname) != null) { recheckOverride(pname, allowedState, context); return true; } @@ -241,7 +237,7 @@ public final class CompatChange extends CompatibilityChangeInfo { if (app == null) { return defaultValue(); } - if (mEvaluatedOverrides != null && mEvaluatedOverrides.containsKey(app.packageName)) { + if (mEvaluatedOverrides.containsKey(app.packageName)) { return mEvaluatedOverrides.get(app.packageName); } if (getDisabled()) { @@ -289,7 +285,7 @@ public final class CompatChange extends CompatibilityChangeInfo { * @return true if there is such override */ private boolean hasOverride(String packageName) { - return mEvaluatedOverrides != null && mEvaluatedOverrides.containsKey(packageName); + return mEvaluatedOverrides.containsKey(packageName); } /** @@ -298,20 +294,15 @@ public final class CompatChange extends CompatibilityChangeInfo { * @return true if there is such a deferred override */ private boolean hasRawOverride(String packageName) { - return mRawOverrides != null && mRawOverrides.containsKey(packageName); + return mRawOverrides.containsKey(packageName); } - void loadOverrides(ChangeOverrides changeOverrides) { - if (mRawOverrides == null) { - mRawOverrides = new HashMap<>(); - } + void clearOverrides() { mRawOverrides.clear(); - - if (mEvaluatedOverrides == null) { - mEvaluatedOverrides = new HashMap<>(); - } mEvaluatedOverrides.clear(); + } + void loadOverrides(ChangeOverrides changeOverrides) { // Load deferred overrides for backwards compatibility if (changeOverrides.getDeferred() != null) { for (OverrideValue override : changeOverrides.getDeferred().getOverrideValue()) { @@ -345,34 +336,30 @@ public final class CompatChange extends CompatibilityChangeInfo { } ChangeOverrides saveOverrides() { - if (mRawOverrides == null || mRawOverrides.isEmpty()) { + if (mRawOverrides.isEmpty()) { return null; } ChangeOverrides changeOverrides = new ChangeOverrides(); changeOverrides.setChangeId(getId()); ChangeOverrides.Raw rawOverrides = new ChangeOverrides.Raw(); List<RawOverrideValue> rawList = rawOverrides.getRawOverrideValue(); - if (mRawOverrides != null) { - for (Map.Entry<String, PackageOverride> entry : mRawOverrides.entrySet()) { - RawOverrideValue override = new RawOverrideValue(); - override.setPackageName(entry.getKey()); - override.setMinVersionCode(entry.getValue().getMinVersionCode()); - override.setMaxVersionCode(entry.getValue().getMaxVersionCode()); - override.setEnabled(entry.getValue().getEnabled()); - rawList.add(override); - } + for (Map.Entry<String, PackageOverride> entry : mRawOverrides.entrySet()) { + RawOverrideValue override = new RawOverrideValue(); + override.setPackageName(entry.getKey()); + override.setMinVersionCode(entry.getValue().getMinVersionCode()); + override.setMaxVersionCode(entry.getValue().getMaxVersionCode()); + override.setEnabled(entry.getValue().getEnabled()); + rawList.add(override); } changeOverrides.setRaw(rawOverrides); ChangeOverrides.Validated validatedOverrides = new ChangeOverrides.Validated(); List<OverrideValue> validatedList = validatedOverrides.getOverrideValue(); - if (mEvaluatedOverrides != null) { - for (Map.Entry<String, Boolean> entry : mEvaluatedOverrides.entrySet()) { - OverrideValue override = new OverrideValue(); - override.setPackageName(entry.getKey()); - override.setEnabled(entry.getValue()); - validatedList.add(override); - } + for (Map.Entry<String, Boolean> entry : mEvaluatedOverrides.entrySet()) { + OverrideValue override = new OverrideValue(); + override.setPackageName(entry.getKey()); + override.setEnabled(entry.getValue()); + validatedList.add(override); } changeOverrides.setValidated(validatedOverrides); return changeOverrides; @@ -394,10 +381,10 @@ public final class CompatChange extends CompatibilityChangeInfo { if (getLoggingOnly()) { sb.append("; loggingOnly"); } - if (mEvaluatedOverrides != null && mEvaluatedOverrides.size() > 0) { + if (!mEvaluatedOverrides.isEmpty()) { sb.append("; packageOverrides=").append(mEvaluatedOverrides); } - if (mRawOverrides != null && mRawOverrides.size() > 0) { + if (!mRawOverrides.isEmpty()) { sb.append("; rawOverrides=").append(mRawOverrides); } if (getOverridable()) { diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java index 66a652053857..2c053b421904 100644 --- a/services/core/java/com/android/server/compat/CompatConfig.java +++ b/services/core/java/com/android/server/compat/CompatConfig.java @@ -67,6 +67,7 @@ final class CompatConfig { private static final String TAG = "CompatConfig"; private static final String APP_COMPAT_DATA_DIR = "/data/misc/appcompat"; + private static final String STATIC_OVERRIDES_PRODUCT_DIR = "/product/etc/appcompat"; private static final String OVERRIDES_FILE = "compat_framework_overrides.xml"; @GuardedBy("mChanges") @@ -94,8 +95,7 @@ final class CompatConfig { config.initConfigFromLib(Environment.buildPath( apex.apexDirectory, "etc", "compatconfig")); } - File overridesFile = new File(APP_COMPAT_DATA_DIR, OVERRIDES_FILE); - config.initOverrides(overridesFile); + config.initOverrides(); config.invalidateCache(); return config; } @@ -525,10 +525,34 @@ final class CompatConfig { } } - void initOverrides(File overridesFile) { + private void initOverrides() { + initOverrides(new File(APP_COMPAT_DATA_DIR, OVERRIDES_FILE), + new File(STATIC_OVERRIDES_PRODUCT_DIR, OVERRIDES_FILE)); + } + + @VisibleForTesting + void initOverrides(File dynamicOverridesFile, File staticOverridesFile) { + // Clear overrides from all changes before loading. + synchronized (mChanges) { + for (int i = 0; i < mChanges.size(); ++i) { + mChanges.valueAt(i).clearOverrides(); + } + } + + loadOverrides(staticOverridesFile); + + mOverridesFile = dynamicOverridesFile; + loadOverrides(dynamicOverridesFile); + + if (staticOverridesFile.exists()) { + // Only save overrides if there is a static overrides file. + saveOverrides(); + } + } + + private void loadOverrides(File overridesFile) { if (!overridesFile.exists()) { - mOverridesFile = overridesFile; - // There have not been any overrides added yet. + // Overrides file doesn't exist. return; } @@ -548,7 +572,6 @@ final class CompatConfig { Slog.w(TAG, "Error processing " + overridesFile + " " + e.toString()); return; } - mOverridesFile = overridesFile; } /** diff --git a/services/core/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/connectivity/DataConnectionStats.java index fbd089c1f0ee..15f43a0481bd 100644 --- a/services/core/java/com/android/server/connectivity/DataConnectionStats.java +++ b/services/core/java/com/android/server/connectivity/DataConnectionStats.java @@ -52,6 +52,7 @@ public class DataConnectionStats extends BroadcastReceiver { private SignalStrength mSignalStrength; private ServiceState mServiceState; private int mDataState = TelephonyManager.DATA_DISCONNECTED; + private int mNrState = NetworkRegistrationInfo.NR_STATE_NONE; public DataConnectionStats(Context context, Handler listenerHandler) { mContext = context; @@ -99,7 +100,7 @@ public class DataConnectionStats extends BroadcastReceiver { : regInfo.getAccessNetworkTechnology(); // If the device is in NSA NR connection the networkType will report as LTE. // For cell dwell rate metrics, this should report NR instead. - if (regInfo != null && regInfo.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED) { + if (mNrState == NetworkRegistrationInfo.NR_STATE_CONNECTED) { networkType = TelephonyManager.NETWORK_TYPE_NR; } if (DEBUG) Log.d(TAG, String.format("Noting data connection for network type %s: %svisible", @@ -171,6 +172,7 @@ public class DataConnectionStats extends BroadcastReceiver { @Override public void onServiceStateChanged(ServiceState state) { mServiceState = state; + mNrState = state.getNrState(); notePhoneDataConnectionState(); } diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index 34d9ccc15dba..7b20ded19205 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -57,8 +57,8 @@ import android.util.Log; import android.util.Pair; import com.android.internal.R; -import com.android.internal.util.HexDump; import com.android.internal.util.IndentingPrintWriter; +import com.android.net.module.util.HexDump; import com.android.net.module.util.IpUtils; import java.io.FileDescriptor; diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java index 641287f0f435..fa80b25f9026 100644 --- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java @@ -29,14 +29,12 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkInfo; import android.net.RouteInfo; -import android.os.INetworkManagementService; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.NetworkStackConstants; -import com.android.server.net.BaseNetworkObserver; import java.net.Inet6Address; import java.util.Objects; @@ -48,7 +46,7 @@ import java.util.Objects; * * @hide */ -public class Nat464Xlat extends BaseNetworkObserver { +public class Nat464Xlat { private static final String TAG = Nat464Xlat.class.getSimpleName(); // This must match the interface prefix in clatd.c. @@ -70,7 +68,6 @@ public class Nat464Xlat extends BaseNetworkObserver { private final IDnsResolver mDnsResolver; private final INetd mNetd; - private final INetworkManagementService mNMService; // The network we're running on, and its type. private final NetworkAgentInfo mNetwork; @@ -99,11 +96,9 @@ public class Nat464Xlat extends BaseNetworkObserver { private boolean mPrefixDiscoveryRunning; - public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver, - INetworkManagementService nmService) { + public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver) { mDnsResolver = dnsResolver; mNetd = netd; - mNMService = nmService; mNetwork = nai; } @@ -174,13 +169,6 @@ public class Nat464Xlat extends BaseNetworkObserver { * and set internal state. */ private void enterStartingState(String baseIface) { - try { - mNMService.registerObserver(this); - } catch (RemoteException e) { - Log.e(TAG, "Can't register iface observer for clat on " + mNetwork.toShortString()); - return; - } - mNat64PrefixInUse = selectNat64Prefix(); String addrStr = null; try { @@ -216,11 +204,6 @@ public class Nat464Xlat extends BaseNetworkObserver { * Unregister as a base observer for the stacked interface, and clear internal state. */ private void leaveStartedState() { - try { - mNMService.unregisterObserver(this); - } catch (RemoteException | IllegalStateException e) { - Log.e(TAG, "Error unregistering clatd observer on " + mBaseIface + ": " + e); - } mNat64PrefixInUse = null; mIface = null; mBaseIface = null; @@ -507,12 +490,10 @@ public class Nat464Xlat extends BaseNetworkObserver { stop(); } - @Override public void interfaceLinkStateChanged(String iface, boolean up) { mNetwork.handler().post(() -> { handleInterfaceLinkStateChanged(iface, up); }); } - @Override public void interfaceRemoved(String iface) { mNetwork.handler().post(() -> handleInterfaceRemoved(iface)); } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 4cf527415d7e..cac6cab7074e 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -43,7 +43,6 @@ import android.net.QosSession; import android.net.TcpKeepalivePacketData; import android.os.Handler; import android.os.IBinder; -import android.os.INetworkManagementService; import android.os.RemoteException; import android.os.SystemClock; import android.telephony.data.EpsBearerQosSessionAttributes; @@ -341,8 +340,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info, @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc, int score, Context context, Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd, - IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber, - int creatorUid, QosCallbackTracker qosCallbackTracker) { + IDnsResolver dnsResolver, int factorySerialNumber, int creatorUid, + QosCallbackTracker qosCallbackTracker) { Objects.requireNonNull(net); Objects.requireNonNull(info); Objects.requireNonNull(lp); @@ -356,7 +355,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { linkProperties = lp; networkCapabilities = nc; mScore = score; - clatd = new Nat464Xlat(this, netd, dnsResolver, nms); + clatd = new Nat464Xlat(this, netd, dnsResolver); mConnService = connService; mContext = context; mHandler = handler; diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java index 835b4688dd4e..658d27f43313 100644 --- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java +++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java @@ -425,7 +425,13 @@ public final class DeviceStateManagerService extends SystemService { if (!mRequestRecords.isEmpty()) { final OverrideRequestRecord topRequest = mRequestRecords.get(mRequestRecords.size() - 1); - topRequest.setStatusLocked(OverrideRequestRecord.STATUS_ACTIVE); + if (topRequest.mRequestedState.getIdentifier() == mCommittedState.getIdentifier()) { + // The top request could have come in while the service was awaiting callback + // from the policy. In that case we only set it to active if it matches the + // current committed state, otherwise it will be set to active when its + // requested state is committed. + topRequest.setStatusLocked(OverrideRequestRecord.STATUS_ACTIVE); + } } mPendingState = Optional.empty(); @@ -563,10 +569,13 @@ public final class DeviceStateManagerService extends SystemService { new OverrideRequestRecord(processRecord, token, deviceState.get(), flags); mRequestRecords.add(request); processRecord.mRequestRecords.put(request.mToken, request); - // We don't set the status of the new request to ACTIVE here as it will be set in - // commitPendingState(). - updatePendingStateLocked(); + final boolean updatedPendingState = updatePendingStateLocked(); + if (!updatedPendingState && !mPendingState.isPresent()) { + // We don't set the status of the new request to ACTIVE if the request updated the + // pending state as it will be set in commitPendingState(). + request.setStatusLocked(OverrideRequestRecord.STATUS_ACTIVE, true /* markDirty */); + } } notifyRequestsOfStatusChangeIfNeeded(); diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index dce6bd849953..645ca7ac33e0 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -31,7 +31,6 @@ import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.os.PowerManager; import android.os.SystemClock; import android.os.UserHandle; import android.provider.DeviceConfig; @@ -80,6 +79,8 @@ public class DisplayModeDirector { // specific display. private static final int GLOBAL_ID = -1; + private static final int INVALID_DISPLAY_MODE_ID = -1; + // The tolerance within which we consider something approximately equals. private static final float FLOAT_TOLERANCE = 0.01f; @@ -322,12 +323,30 @@ public class DisplayModeDirector { appRequestSummary.maxRefreshRate)); } - // If the application requests a given mode with preferredModeId function, it will be - // stored as baseModeId. - int baseModeId = defaultMode.getModeId(); - if (availableModes.length > 0) { + int baseModeId = INVALID_DISPLAY_MODE_ID; + + // Select the default mode if available. This is important because SurfaceFlinger + // can do only seamless switches by default. Some devices (e.g. TV) don't support + // seamless switching so the mode we select here won't be changed. + for (int availableMode : availableModes) { + if (availableMode == defaultMode.getModeId()) { + baseModeId = defaultMode.getModeId(); + break; + } + } + + // If the application requests a display mode by setting + // LayoutParams.preferredDisplayModeId, it will be the only available mode and it'll + // be stored as baseModeId. + if (baseModeId == INVALID_DISPLAY_MODE_ID && availableModes.length > 0) { baseModeId = availableModes[0]; } + + if (baseModeId == INVALID_DISPLAY_MODE_ID) { + throw new IllegalStateException("Can't select a base display mode for display " + + displayId + ". The votes are " + mVotesByDisplay.valueAt(displayId)); + } + if (mModeSwitchingType == DisplayManager.SWITCHING_TYPE_NONE) { Display.Mode baseMode = null; for (Display.Mode mode : modes) { @@ -351,6 +370,7 @@ public class DisplayModeDirector { boolean allowGroupSwitching = mModeSwitchingType == DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS; + return new DesiredDisplayModeSpecs(baseModeId, allowGroupSwitching, new RefreshRateRange( diff --git a/services/core/java/com/android/server/graphics/fonts/FontCrashDetector.java b/services/core/java/com/android/server/graphics/fonts/FontCrashDetector.java deleted file mode 100644 index b082b25aea02..000000000000 --- a/services/core/java/com/android/server/graphics/fonts/FontCrashDetector.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.graphics.fonts; - -import android.annotation.NonNull; -import android.util.Slog; - -import java.io.File; -import java.io.IOException; - -/** - * A class to detect font-related native crash. - * - * <p>If a fs-verity protected file is accessed through mmap and corrupted file block is detected, - * SIGBUG signal is generated and the process will crash. To find corrupted files and remove them, - * we use a marker file to detect crash. - * <ol> - * <li>Create a marker file before reading fs-verity protected font files. - * <li>Delete the marker file after reading font files successfully. - * <li>If the marker file is found in the next process startup, it means that the process - * crashed before. We will delete font files to prevent crash loop. - * </ol> - * - * <p>Example usage: - * <pre> - * FontCrashDetector detector = new FontCrashDetector(new File("/path/to/marker_file")); - * if (detector.hasCrashed()) { - * // Do cleanup - * } - * try (FontCrashDetector.MonitoredBlock b = detector.start()) { - * // Read files - * } - * </pre> - * - * <p>This class DOES NOT detect Java exceptions. If a Java exception is thrown while monitoring - * crash, the marker file will be deleted. Creating and deleting marker files are not lightweight. - * Please use this class sparingly with caution. - */ -/* package */ final class FontCrashDetector { - - private static final String TAG = "FontCrashDetector"; - - @NonNull - private final File mMarkerFile; - - /* package */ FontCrashDetector(@NonNull File markerFile) { - mMarkerFile = markerFile; - } - - /* package */ boolean hasCrashed() { - return mMarkerFile.exists(); - } - - /* package */ void clear() { - if (!mMarkerFile.delete()) { - Slog.e(TAG, "Could not delete marker file: " + mMarkerFile); - } - } - - /** Starts crash monitoring. */ - /* package */ MonitoredBlock start() { - try { - mMarkerFile.createNewFile(); - } catch (IOException e) { - Slog.e(TAG, "Could not create marker file: " + mMarkerFile, e); - } - return new MonitoredBlock(); - } - - /** A helper class to monitor crash with try-with-resources syntax. */ - /* package */ class MonitoredBlock implements AutoCloseable { - /** Ends crash monitoring. */ - @Override - public void close() { - clear(); - } - } -} diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java index 01e839dae07a..900ec905609f 100644 --- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java +++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java @@ -63,7 +63,6 @@ public final class FontManagerService extends IFontManager.Stub { private static final String TAG = "FontManagerService"; private static final String FONT_FILES_DIR = "/data/fonts/files"; - private static final String CRASH_MARKER_FILE = "/data/fonts/config/crash.txt"; @Override public FontConfig getFontConfig() { @@ -200,10 +199,6 @@ public final class FontManagerService extends IFontManager.Stub { private final Object mUpdatableFontDirLock = new Object(); @GuardedBy("mUpdatableFontDirLock") - @NonNull - private final FontCrashDetector mFontCrashDetector; - - @GuardedBy("mUpdatableFontDirLock") @Nullable private final UpdatableFontDir mUpdatableFontDir; @@ -217,7 +212,6 @@ public final class FontManagerService extends IFontManager.Stub { private FontManagerService(Context context) { mContext = context; - mFontCrashDetector = new FontCrashDetector(new File(CRASH_MARKER_FILE)); mUpdatableFontDir = createUpdatableFontDir(); initialize(); } @@ -244,19 +238,8 @@ public final class FontManagerService extends IFontManager.Stub { } return; } - if (mFontCrashDetector.hasCrashed()) { - Slog.i(TAG, "Crash detected. Clearing font updates."); - try { - mUpdatableFontDir.clearUpdates(); - } catch (SystemFontException e) { - Slog.e(TAG, "Failed to clear updates.", e); - } - mFontCrashDetector.clear(); - } - try (FontCrashDetector.MonitoredBlock ignored = mFontCrashDetector.start()) { - mUpdatableFontDir.loadFontFileMap(); - updateSerializedFontMap(); - } + mUpdatableFontDir.loadFontFileMap(); + updateSerializedFontMap(); } } @@ -286,10 +269,8 @@ public final class FontManagerService extends IFontManager.Stub { FontManager.RESULT_ERROR_VERSION_MISMATCH, "The base config version is older than current."); } - try (FontCrashDetector.MonitoredBlock ignored = mFontCrashDetector.start()) { - mUpdatableFontDir.update(requests); - updateSerializedFontMap(); - } + mUpdatableFontDir.update(requests); + updateSerializedFontMap(); } } @@ -300,10 +281,8 @@ public final class FontManagerService extends IFontManager.Stub { "The font updater is disabled."); } synchronized (mUpdatableFontDirLock) { - try (FontCrashDetector.MonitoredBlock ignored = mFontCrashDetector.start()) { - mUpdatableFontDir.clearUpdates(); - updateSerializedFontMap(); - } + mUpdatableFontDir.clearUpdates(); + updateSerializedFontMap(); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index b4d9b01f716f..115cafedca93 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -221,7 +221,7 @@ public class HdmiControlService extends SystemService { private int mHdmiCecVolumeControl; // Make sure HdmiCecConfig is instantiated and the XMLs are read. - private final HdmiCecConfig mHdmiCecConfig; + private HdmiCecConfig mHdmiCecConfig; /** * Interface to report send result. @@ -580,6 +580,11 @@ public class HdmiControlService extends SystemService { mHdmiCecNetwork = hdmiCecNetwork; } + @VisibleForTesting + void setHdmiCecConfig(HdmiCecConfig hdmiCecConfig) { + mHdmiCecConfig = hdmiCecConfig; + } + public HdmiCecNetwork getHdmiCecNetwork() { return mHdmiCecNetwork; } diff --git a/services/core/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java index 3ac148ddab1b..c93c4b1f21b7 100644 --- a/services/core/java/com/android/server/location/GeocoderProxy.java +++ b/services/core/java/com/android/server/location/GeocoderProxy.java @@ -24,7 +24,7 @@ import android.location.IGeocodeProvider; import android.os.IBinder; import android.os.RemoteException; -import com.android.server.ServiceWatcher; +import com.android.server.servicewatcher.ServiceWatcher; import java.util.Collections; diff --git a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java index 6ea4bd2b1d6d..e1c87000ea89 100644 --- a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java +++ b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java @@ -25,8 +25,8 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Log; -import com.android.server.ServiceWatcher; -import com.android.server.ServiceWatcher.BoundService; +import com.android.server.servicewatcher.ServiceWatcher; +import com.android.server.servicewatcher.ServiceWatcher.BoundService; /** * Proxy class to bind GmsCore to the ActivityRecognitionHardware. diff --git a/services/core/java/com/android/server/location/geofence/GeofenceProxy.java b/services/core/java/com/android/server/location/geofence/GeofenceProxy.java index bdfa6d7aa67e..c70714932792 100644 --- a/services/core/java/com/android/server/location/geofence/GeofenceProxy.java +++ b/services/core/java/com/android/server/location/geofence/GeofenceProxy.java @@ -29,7 +29,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; -import com.android.server.ServiceWatcher; +import com.android.server.servicewatcher.ServiceWatcher; import java.util.Objects; diff --git a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java index 44b62b3659dc..c86e49bc7948 100644 --- a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java +++ b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java @@ -36,9 +36,9 @@ import android.util.ArraySet; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; -import com.android.server.ServiceWatcher; -import com.android.server.ServiceWatcher.BoundService; import com.android.server.location.provider.AbstractLocationProvider; +import com.android.server.servicewatcher.ServiceWatcher; +import com.android.server.servicewatcher.ServiceWatcher.BoundService; import java.io.FileDescriptor; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 5b9a11bc5a31..3a5e10ed951a 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -97,7 +97,7 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkIdentity; import android.net.NetworkStack; -import android.net.NetworkState; +import android.net.NetworkStateSnapshot; import android.net.NetworkStats; import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; @@ -296,7 +296,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Last states of all networks sent from ConnectivityService. */ @GuardedBy("mStatsLock") @Nullable - private NetworkState[] mLastNetworkStates = null; + private NetworkStateSnapshot[] mLastNetworkStateSnapshots = null; private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); @@ -378,8 +378,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } case MSG_UPDATE_IFACES: { // If no cached states, ignore. - if (mLastNetworkStates == null) break; - updateIfaces(mDefaultNetworks, mLastNetworkStates, mActiveIface); + if (mLastNetworkStateSnapshots == null) break; + updateIfaces(mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface); break; } case MSG_PERFORM_POLL_REGISTER_ALERT: { @@ -967,10 +967,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - @Override public void forceUpdateIfaces( Network[] defaultNetworks, - NetworkState[] networkStates, + NetworkStateSnapshot[] networkStates, String activeIface, UnderlyingNetworkInfo[] underlyingNetworkInfos) { checkNetworkStackPermission(mContext); @@ -1248,13 +1247,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void updateIfaces( Network[] defaultNetworks, - NetworkState[] networkStates, + NetworkStateSnapshot[] snapshots, String activeIface) { synchronized (mStatsLock) { mWakeLock.acquire(); try { mActiveIface = activeIface; - updateIfacesLocked(defaultNetworks, networkStates); + updateIfacesLocked(defaultNetworks, snapshots); } finally { mWakeLock.release(); } @@ -1262,13 +1261,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * Inspect all current {@link NetworkState} to derive mapping from {@code iface} to {@link - * NetworkStatsHistory}. When multiple networks are active on a single {@code iface}, + * Inspect all current {@link NetworkStateSnapshot}s to derive mapping from {@code iface} to + * {@link NetworkStatsHistory}. When multiple networks are active on a single {@code iface}, * they are combined under a single {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") private void updateIfacesLocked(@Nullable Network[] defaultNetworks, - @NonNull NetworkState[] states) { + @NonNull NetworkStateSnapshot[] snapshots) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -1288,21 +1287,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mDefaultNetworks = defaultNetworks; } - mLastNetworkStates = states; + mLastNetworkStateSnapshots = snapshots; final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled(); final ArraySet<String> mobileIfaces = new ArraySet<>(); - for (NetworkState state : states) { - final boolean isMobile = isNetworkTypeMobile(state.legacyNetworkType); - final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network); + for (NetworkStateSnapshot snapshot : snapshots) { + final boolean isMobile = isNetworkTypeMobile(snapshot.legacyType); + final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.network); final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED - : getSubTypeForState(state); - final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state, + : getSubTypeForStateSnapshot(snapshot); + final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot, isDefault, subType); // Traffic occurring on the base interface is always counted for // both total usage and UID details. - final String baseIface = state.linkProperties.getInterfaceName(); + final String baseIface = snapshot.linkProperties.getInterfaceName(); if (baseIface != null) { findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident); findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident); @@ -1312,7 +1311,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // If IMS is metered, then the IMS network usage has already included VT usage. // VT is considered always metered in framework's layer. If VT is not metered // per carrier's policy, modem will report 0 usage for VT calls. - if (state.networkCapabilities.hasCapability( + if (snapshot.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.getMetered()) { // Copy the identify from IMS one but mark it as metered. @@ -1358,7 +1357,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // (or non eBPF offloaded) TX they would appear on both, however egress interface // accounting is explicitly bypassed for traffic from the clat uid. // - final List<LinkProperties> stackedLinks = state.linkProperties.getStackedLinks(); + final List<LinkProperties> stackedLinks = snapshot.linkProperties.getStackedLinks(); for (LinkProperties stackedLink : stackedLinks) { final String stackedIface = stackedLink.getInterfaceName(); if (stackedIface != null) { @@ -1381,7 +1380,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different * transport types do not actually fill this value. */ - private int getSubTypeForState(@NonNull NetworkState state) { + private int getSubTypeForStateSnapshot(@NonNull NetworkStateSnapshot state) { if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { return 0; } diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java index 9a9b14c31314..b34611b9cd6f 100644 --- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java +++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java @@ -207,35 +207,37 @@ public class DataLoaderManagerService extends SystemService { @Override public void onServiceDisconnected(ComponentName arg0) { Slog.i(TAG, "DataLoader " + mId + " disconnected, but will try to recover"); - callListener(IDataLoaderStatusListener.DATA_LOADER_DESTROYED); - destroy(); + unbindAndReportDestroyed(); } @Override public void onBindingDied(ComponentName name) { Slog.i(TAG, "DataLoader " + mId + " died"); - callListener(IDataLoaderStatusListener.DATA_LOADER_DESTROYED); - destroy(); + unbindAndReportDestroyed(); } @Override public void onNullBinding(ComponentName name) { Slog.i(TAG, "DataLoader " + mId + " failed to start"); - callListener(IDataLoaderStatusListener.DATA_LOADER_DESTROYED); - destroy(); + unbindAndReportDestroyed(); } @Override public void binderDied() { Slog.i(TAG, "DataLoader " + mId + " died"); - callListener(IDataLoaderStatusListener.DATA_LOADER_DESTROYED); - destroy(); + unbindAndReportDestroyed(); } IDataLoader getDataLoader() { return mDataLoader; } + private void unbindAndReportDestroyed() { + if (unbind()) { + callListener(IDataLoaderStatusListener.DATA_LOADER_DESTROYED); + } + } + void destroy() { if (mDataLoader != null) { try { @@ -244,11 +246,15 @@ public class DataLoaderManagerService extends SystemService { } mDataLoader = null; } + unbind(); + } + + boolean unbind() { try { mContext.unbindService(this); } catch (Exception ignored) { } - remove(); + return remove(); } private boolean append() { @@ -266,12 +272,14 @@ public class DataLoaderManagerService extends SystemService { } } - private void remove() { + private boolean remove() { synchronized (mServiceConnections) { if (mServiceConnections.get(mId) == this) { mServiceConnections.remove(mId); + return true; } } + return false; } private void callListener(int status) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e3f925a97dda..06b85cfbd404 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -11634,9 +11634,17 @@ public class PackageManagerService extends IPackageManager.Stub healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS; healthCheckParams.unhealthyMonitoringMs = INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS; + // Continue monitoring health and loading progress of active incremental packages mIncrementalManager.registerHealthListener(parsedPackage.getPath(), healthCheckParams, new IncrementalHealthListener(parsedPackage.getPackageName())); + final IncrementalStatesCallback incrementalStatesCallback = + new IncrementalStatesCallback(parsedPackage.getPackageName(), + UserHandle.getUid(UserHandle.ALL, pkgSetting.appId), + getInstalledUsers(pkgSetting, UserHandle.USER_ALL)); + pkgSetting.setIncrementalStatesCallback(incrementalStatesCallback); + mIncrementalManager.registerLoadingProgressCallback(parsedPackage.getPath(), + new IncrementalProgressListener(parsedPackage.getPackageName())); } } return scanResult.pkgSetting.pkg; @@ -19420,6 +19428,8 @@ public class PackageManagerService extends IPackageManager.Stub mIncrementalManager.unregisterLoadingProgressCallbacks(codePath); // Unregister health listener as it will always be healthy from now mIncrementalManager.unregisterHealthListener(codePath); + // Make sure the information is preserved + scheduleWriteSettingsLocked(); } @Override @@ -19482,11 +19492,11 @@ public class PackageManagerService extends IPackageManager.Stub final PackageSetting ps; synchronized (mLock) { ps = mSettings.getPackageLPr(mPackageName); + if (ps == null) { + return; + } + ps.setLoadingProgress(progress); } - if (ps == null) { - return; - } - ps.setLoadingProgress(progress); } } @@ -20090,7 +20100,7 @@ public class PackageManagerService extends IPackageManager.Stub } catch (PackageManagerException pme) { Slog.e(TAG, "Error deriving application ABI", pme); throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR, - "Error deriving application ABI"); + "Error deriving application ABI: " + pme.getMessage()); } } diff --git a/services/core/java/com/android/server/servicewatcher/OWNERS b/services/core/java/com/android/server/servicewatcher/OWNERS new file mode 100644 index 000000000000..ced619f05f1d --- /dev/null +++ b/services/core/java/com/android/server/servicewatcher/OWNERS @@ -0,0 +1,5 @@ +# Bug component: 25692 + +sooniln@google.com +wyattriley@google.com + diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/servicewatcher/ServiceWatcher.java index 8a2894c84cc4..5d49663209b7 100644 --- a/services/core/java/com/android/server/ServiceWatcher.java +++ b/services/core/java/com/android/server/servicewatcher/ServiceWatcher.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.servicewatcher; import static android.content.Context.BIND_AUTO_CREATE; import static android.content.Context.BIND_NOT_FOREGROUND; @@ -52,6 +52,7 @@ import com.android.internal.annotations.Immutable; import com.android.internal.content.PackageMonitor; import com.android.internal.util.Preconditions; import com.android.internal.util.function.pooled.PooledLambda; +import com.android.server.FgThread; import java.io.FileDescriptor; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java index 531c62c5b4e9..0b51488280e0 100644 --- a/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java +++ b/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java @@ -39,8 +39,8 @@ import android.service.timezone.TimeZoneProviderSuggestion; import android.util.IndentingPrintWriter; import com.android.internal.annotations.GuardedBy; -import com.android.server.ServiceWatcher; -import com.android.server.ServiceWatcher.BoundService; +import com.android.server.servicewatcher.ServiceWatcher; +import com.android.server.servicewatcher.ServiceWatcher.BoundService; import java.util.Objects; import java.util.function.Predicate; diff --git a/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java b/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java index 685dce4683d7..96f84dc65e1d 100644 --- a/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java +++ b/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java @@ -16,6 +16,7 @@ package com.android.server.vibrator; +import android.annotation.Nullable; import android.content.Context; import android.hardware.input.InputManager; import android.os.CombinedVibrationEffect; @@ -33,7 +34,11 @@ final class InputDeviceDelegate implements InputManager.InputDeviceListener { private final Object mLock = new Object(); private final Handler mHandler; - private final InputManager mInputManager; + private final Context mContext; + + @GuardedBy("mLock") + @Nullable + private InputManager mInputManager; @GuardedBy("mLock") private final SparseArray<VibratorManager> mInputDeviceVibrators = new SparseArray<>(); @@ -47,7 +52,13 @@ final class InputDeviceDelegate implements InputManager.InputDeviceListener { InputDeviceDelegate(Context context, Handler handler) { mHandler = handler; - mInputManager = context.getSystemService(InputManager.class); + mContext = context; + } + + public void onSystemReady() { + synchronized (mLock) { + mInputManager = mContext.getSystemService(InputManager.class); + } } @Override @@ -116,6 +127,10 @@ final class InputDeviceDelegate implements InputManager.InputDeviceListener { */ public boolean updateInputDeviceVibrators(boolean vibrateInputDevices) { synchronized (mLock) { + if (mInputManager == null) { + // Ignore update, service not loaded yet so change cannot be applied. + return false; + } if (vibrateInputDevices == mShouldVibrateInputDevices) { // No need to update if settings haven't changed. return false; @@ -150,6 +165,10 @@ final class InputDeviceDelegate implements InputManager.InputDeviceListener { private void updateInputDevice(int deviceId) { synchronized (mLock) { + if (mInputManager == null) { + // Ignore update, service not loaded yet so change cannot be applied. + return; + } if (!mShouldVibrateInputDevices) { // No need to keep this device vibrator if setting is off. return; diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java index 334129d6bde9..4a07c1ac1e39 100644 --- a/services/core/java/com/android/server/vibrator/VibrationSettings.java +++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java @@ -16,6 +16,7 @@ package com.android.server.vibrator; +import android.annotation.Nullable; import android.app.ActivityManager; import android.app.IUidObserver; import android.content.Context; @@ -57,8 +58,6 @@ final class VibrationSettings { private final Object mLock = new Object(); private final Context mContext; - private final Vibrator mVibrator; - private final AudioManager mAudioManager; private final SettingsObserver mSettingObserver; @VisibleForTesting final UidObserver mUidObserver; @@ -68,6 +67,13 @@ final class VibrationSettings { private final SparseArray<VibrationEffect> mFallbackEffects; @GuardedBy("mLock") + @Nullable + private Vibrator mVibrator; + @GuardedBy("mLock") + @Nullable + private AudioManager mAudioManager; + + @GuardedBy("mLock") private boolean mVibrateInputDevices; @GuardedBy("mLock") private boolean mVibrateWhenRinging; @@ -86,22 +92,9 @@ final class VibrationSettings { VibrationSettings(Context context, Handler handler) { mContext = context; - mVibrator = context.getSystemService(Vibrator.class); - mAudioManager = context.getSystemService(AudioManager.class); mSettingObserver = new SettingsObserver(handler); mUidObserver = new UidObserver(); - registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES)); - registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_WHEN_RINGING)); - registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.APPLY_RAMPING_RINGER)); - registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.ZEN_MODE)); - registerSettingsObserver( - Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY)); - registerSettingsObserver( - Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY)); - registerSettingsObserver( - Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY)); - VibrationEffect clickEffect = createEffectFromResource( com.android.internal.R.array.config_virtualKeyVibePattern); VibrationEffect doubleClickEffect = VibrationEffect.createWaveform( @@ -119,6 +112,15 @@ final class VibrationSettings { mFallbackEffects.put(VibrationEffect.EFFECT_TEXTURE_TICK, VibrationEffect.get(VibrationEffect.EFFECT_TICK, false)); + // Update with current values from settings. + updateSettings(); + } + + public void onSystemReady() { + synchronized (mLock) { + mVibrator = mContext.getSystemService(Vibrator.class); + mAudioManager = mContext.getSystemService(AudioManager.class); + } try { ActivityManager.getService().registerUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE, @@ -148,7 +150,18 @@ final class VibrationSettings { } }); - // Update with current values from settings. + registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES)); + registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_WHEN_RINGING)); + registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.APPLY_RAMPING_RINGER)); + registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.ZEN_MODE)); + registerSettingsObserver( + Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY)); + registerSettingsObserver( + Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY)); + registerSettingsObserver( + Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY)); + + // Update with newly loaded services. updateSettings(); } @@ -178,17 +191,21 @@ final class VibrationSettings { * @return The vibration intensity, one of Vibrator.VIBRATION_INTENSITY_* */ public int getDefaultIntensity(int usageHint) { - if (isRingtone(usageHint)) { - return mVibrator.getDefaultRingVibrationIntensity(); - } else if (isNotification(usageHint)) { - return mVibrator.getDefaultNotificationVibrationIntensity(); - } else if (isHapticFeedback(usageHint)) { - return mVibrator.getDefaultHapticFeedbackIntensity(); - } else if (isAlarm(usageHint)) { + if (isAlarm(usageHint)) { return Vibrator.VIBRATION_INTENSITY_HIGH; - } else { - return Vibrator.VIBRATION_INTENSITY_MEDIUM; } + synchronized (mLock) { + if (mVibrator != null) { + if (isRingtone(usageHint)) { + return mVibrator.getDefaultRingVibrationIntensity(); + } else if (isNotification(usageHint)) { + return mVibrator.getDefaultNotificationVibrationIntensity(); + } else if (isHapticFeedback(usageHint)) { + return mVibrator.getDefaultHapticFeedbackIntensity(); + } + } + } + return Vibrator.VIBRATION_INTENSITY_MEDIUM; } /** @@ -234,8 +251,11 @@ final class VibrationSettings { if (!isRingtone(usageHint)) { return true; } - int ringerMode = mAudioManager.getRingerModeInternal(); synchronized (mLock) { + if (mAudioManager == null) { + return false; + } + int ringerMode = mAudioManager.getRingerModeInternal(); if (mVibrateWhenRinging) { return ringerMode != AudioManager.RINGER_MODE_SILENT; } else if (mApplyRampingRinger) { @@ -304,12 +324,12 @@ final class VibrationSettings { mVibrateWhenRinging = getSystemSetting(Settings.System.VIBRATE_WHEN_RINGING, 0) != 0; mApplyRampingRinger = getGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0) != 0; mHapticFeedbackIntensity = getSystemSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, - mVibrator.getDefaultHapticFeedbackIntensity()); + getDefaultIntensity(VibrationAttributes.USAGE_TOUCH)); mNotificationIntensity = getSystemSetting( Settings.System.NOTIFICATION_VIBRATION_INTENSITY, - mVibrator.getDefaultNotificationVibrationIntensity()); + getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION)); mRingIntensity = getSystemSetting(Settings.System.RING_VIBRATION_INTENSITY, - mVibrator.getDefaultRingVibrationIntensity()); + getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE)); mVibrateInputDevices = getSystemSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0) > 0; mZenMode = getGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF); } @@ -346,15 +366,15 @@ final class VibrationSettings { proto.write(VibratorManagerServiceDumpProto.HAPTIC_FEEDBACK_INTENSITY, mHapticFeedbackIntensity); proto.write(VibratorManagerServiceDumpProto.HAPTIC_FEEDBACK_DEFAULT_INTENSITY, - mVibrator.getDefaultHapticFeedbackIntensity()); + getDefaultIntensity(VibrationAttributes.USAGE_TOUCH)); proto.write(VibratorManagerServiceDumpProto.NOTIFICATION_INTENSITY, mNotificationIntensity); proto.write(VibratorManagerServiceDumpProto.NOTIFICATION_DEFAULT_INTENSITY, - mVibrator.getDefaultNotificationVibrationIntensity()); + getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION)); proto.write(VibratorManagerServiceDumpProto.RING_INTENSITY, mRingIntensity); proto.write(VibratorManagerServiceDumpProto.RING_DEFAULT_INTENSITY, - mVibrator.getDefaultRingVibrationIntensity()); + getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE)); } } diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java index 175085475b6c..90a763c260f6 100644 --- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java +++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java @@ -127,9 +127,9 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { @GuardedBy("mLock") private ExternalVibrationHolder mCurrentExternalVibration; - private VibrationSettings mVibrationSettings; - private VibrationScaler mVibrationScaler; - private InputDeviceDelegate mInputDeviceDelegate; + private final VibrationSettings mVibrationSettings; + private final VibrationScaler mVibrationScaler; + private final InputDeviceDelegate mInputDeviceDelegate; private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override @@ -170,6 +170,10 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { mContext = context; mHandler = injector.createHandler(Looper.myLooper()); + mVibrationSettings = new VibrationSettings(mContext, mHandler); + mVibrationScaler = new VibrationScaler(mContext, mVibrationSettings); + mInputDeviceDelegate = new InputDeviceDelegate(mContext, mHandler); + VibrationCompleteListener listener = new VibrationCompleteListener(this); mNativeWrapper = injector.getNativeWrapper(); mNativeWrapper.init(listener); @@ -224,12 +228,12 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { Slog.v(TAG, "Initializing VibratorManager service..."); Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "systemReady"); try { - mVibrationSettings = new VibrationSettings(mContext, mHandler); - mVibrationScaler = new VibrationScaler(mContext, mVibrationSettings); - mInputDeviceDelegate = new InputDeviceDelegate(mContext, mHandler); + mVibrationSettings.onSystemReady(); + mInputDeviceDelegate.onSystemReady(); mVibrationSettings.addListener(this::updateServiceState); + // Will update settings and input devices. updateServiceState(); } finally { Slog.v(TAG, "VibratorManager service initialized"); diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 32152ec85493..af9cdeb52fe3 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -69,6 +69,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; +import static android.view.WindowManager.LayoutParams.TYPE_POINTER; import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; @@ -242,7 +243,7 @@ public class DisplayPolicy { } } - private final SystemGesturesPointerEventListener mSystemGestures; + private SystemGesturesPointerEventListener mSystemGestures; private volatile int mLidState = LID_ABSENT; private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED; @@ -384,7 +385,7 @@ public class DisplayPolicy { private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0; private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1; - private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver; + private GestureNavigationSettingsObserver mGestureNavigationSettingsObserver; private final WindowManagerInternal.AppTransitionListener mAppTransitionListener; @@ -448,119 +449,6 @@ public class DisplayPolicy { final Looper looper = UiThread.getHandler().getLooper(); mHandler = new PolicyHandler(looper); - mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler, - new SystemGesturesPointerEventListener.Callbacks() { - @Override - public void onSwipeFromTop() { - synchronized (mLock) { - if (mStatusBar != null) { - requestTransientBars(mStatusBar); - } - checkAltBarSwipeForTransientBars(ALT_BAR_TOP); - } - } - - @Override - public void onSwipeFromBottom() { - synchronized (mLock) { - if (mNavigationBar != null - && mNavigationBarPosition == NAV_BAR_BOTTOM) { - requestTransientBars(mNavigationBar); - } - checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM); - } - } - - @Override - public void onSwipeFromRight() { - final Region excludedRegion = Region.obtain(); - synchronized (mLock) { - mDisplayContent.calculateSystemGestureExclusion( - excludedRegion, null /* outUnrestricted */); - final boolean excluded = - mSystemGestures.currentGestureStartedInRegion(excludedRegion); - if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_RIGHT - || !excluded && mNavigationBarAlwaysShowOnSideGesture)) { - requestTransientBars(mNavigationBar); - } - checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT); - } - excludedRegion.recycle(); - } - - @Override - public void onSwipeFromLeft() { - final Region excludedRegion = Region.obtain(); - synchronized (mLock) { - mDisplayContent.calculateSystemGestureExclusion( - excludedRegion, null /* outUnrestricted */); - final boolean excluded = - mSystemGestures.currentGestureStartedInRegion(excludedRegion); - if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_LEFT - || !excluded && mNavigationBarAlwaysShowOnSideGesture)) { - requestTransientBars(mNavigationBar); - } - checkAltBarSwipeForTransientBars(ALT_BAR_LEFT); - } - excludedRegion.recycle(); - } - - @Override - public void onFling(int duration) { - if (mService.mPowerManagerInternal != null) { - mService.mPowerManagerInternal.setPowerBoost( - Boost.INTERACTION, duration); - } - } - - @Override - public void onDebug() { - // no-op - } - - private WindowOrientationListener getOrientationListener() { - final DisplayRotation rotation = mDisplayContent.getDisplayRotation(); - return rotation != null ? rotation.getOrientationListener() : null; - } - - @Override - public void onDown() { - final WindowOrientationListener listener = getOrientationListener(); - if (listener != null) { - listener.onTouchStart(); - } - } - - @Override - public void onUpOrCancel() { - final WindowOrientationListener listener = getOrientationListener(); - if (listener != null) { - listener.onTouchEnd(); - } - } - - @Override - public void onMouseHoverAtTop() { - mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); - Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS); - msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS; - mHandler.sendMessageDelayed(msg, 500 /* delayMillis */); - } - - @Override - public void onMouseHoverAtBottom() { - mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); - Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS); - msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION; - mHandler.sendMessageDelayed(msg, 500 /* delayMillis */); - } - - @Override - public void onMouseLeaveFromEdge() { - mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); - } - }); - displayContent.registerPointerEventListener(mSystemGestures); mAppTransitionListener = new WindowManagerInternal.AppTransitionListener() { private Runnable mAppTransitionPending = () -> { @@ -616,7 +504,7 @@ public class DisplayPolicy { mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper, mService.mVrModeEnabled); - // TODO: Make it can take screenshot on external display + // TODO(b/180986447): Make it can take screenshot on external display mScreenshotHelper = displayContent.isDefaultDisplay ? new ScreenshotHelper(mContext) : null; @@ -640,16 +528,6 @@ public class DisplayPolicy { mRefreshRatePolicy = new RefreshRatePolicy(mService, mDisplayContent.getDisplayInfo(), mService.mHighRefreshRateDenylist); - - mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler, - mContext, () -> { - synchronized (mLock) { - onConfigurationChanged(); - mSystemGestures.onConfigurationChanged(); - mDisplayContent.updateSystemGestureExclusion(); - } - }); - mHandler.post(mGestureNavigationSettingsObserver::register); } private void checkAltBarSwipeForTransientBars(@WindowManagerPolicy.AltBarPosition int pos) { @@ -668,12 +546,154 @@ public class DisplayPolicy { } void systemReady() { - mSystemGestures.systemReady(); if (mService.mPointerLocationEnabled) { setPointerLocationEnabled(true); } } + @NonNull + private GestureNavigationSettingsObserver getGestureNavigationSettingsObserver() { + if (mGestureNavigationSettingsObserver == null) { + mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler, + mContext, () -> { + synchronized (mLock) { + onConfigurationChanged(); + getSystemGestures().onConfigurationChanged(); + mDisplayContent.updateSystemGestureExclusion(); + } + }); + mHandler.post(mGestureNavigationSettingsObserver::register); + } + return mGestureNavigationSettingsObserver; + } + + @NonNull + private SystemGesturesPointerEventListener getSystemGestures() { + if (mSystemGestures == null) { + final Context gestureContext = mUiContext.createWindowContext( + mDisplayContent.getDisplay(), TYPE_POINTER, null /* options */); + mSystemGestures = new SystemGesturesPointerEventListener(gestureContext, mHandler, + new SystemGesturesPointerEventListener.Callbacks() { + @Override + public void onSwipeFromTop() { + synchronized (mLock) { + if (mStatusBar != null) { + requestTransientBars(mStatusBar); + } + checkAltBarSwipeForTransientBars(ALT_BAR_TOP); + } + } + + @Override + public void onSwipeFromBottom() { + synchronized (mLock) { + if (mNavigationBar != null + && mNavigationBarPosition == NAV_BAR_BOTTOM) { + requestTransientBars(mNavigationBar); + } + checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM); + } + } + + @Override + public void onSwipeFromRight() { + final Region excludedRegion = Region.obtain(); + synchronized (mLock) { + mDisplayContent.calculateSystemGestureExclusion( + excludedRegion, null /* outUnrestricted */); + final boolean excluded = mSystemGestures + .currentGestureStartedInRegion(excludedRegion); + if (mNavigationBar != null + && (mNavigationBarPosition == NAV_BAR_RIGHT + || !excluded && mNavigationBarAlwaysShowOnSideGesture)) { + requestTransientBars(mNavigationBar); + } + checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT); + } + excludedRegion.recycle(); + } + + @Override + public void onSwipeFromLeft() { + final Region excludedRegion = Region.obtain(); + synchronized (mLock) { + mDisplayContent.calculateSystemGestureExclusion( + excludedRegion, null /* outUnrestricted */); + final boolean excluded = mSystemGestures + .currentGestureStartedInRegion(excludedRegion); + if (mNavigationBar != null + && (mNavigationBarPosition == NAV_BAR_LEFT + || !excluded && mNavigationBarAlwaysShowOnSideGesture)) { + requestTransientBars(mNavigationBar); + } + checkAltBarSwipeForTransientBars(ALT_BAR_LEFT); + } + excludedRegion.recycle(); + } + + @Override + public void onFling(int duration) { + if (mService.mPowerManagerInternal != null) { + mService.mPowerManagerInternal.setPowerBoost( + Boost.INTERACTION, duration); + } + } + + @Override + public void onDebug() { + // no-op + } + + private WindowOrientationListener getOrientationListener() { + final DisplayRotation rotation = mDisplayContent.getDisplayRotation(); + return rotation != null ? rotation.getOrientationListener() : null; + } + + @Override + public void onDown() { + final WindowOrientationListener listener = getOrientationListener(); + if (listener != null) { + listener.onTouchStart(); + } + } + + @Override + public void onUpOrCancel() { + final WindowOrientationListener listener = getOrientationListener(); + if (listener != null) { + listener.onTouchEnd(); + } + } + + @Override + public void onMouseHoverAtTop() { + mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); + Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS); + msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS; + mHandler.sendMessageDelayed(msg, 500 /* delayMillis */); + } + + @Override + public void onMouseHoverAtBottom() { + mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); + Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS); + msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION; + mHandler.sendMessageDelayed(msg, 500 /* delayMillis */); + } + + @Override + public void onMouseLeaveFromEdge() { + mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); + } + }); + mDisplayContent.registerPointerEventListener(getSystemGestures()); + if (mService.mSystemReady) { + mSystemGestures.systemReady(); + } + } + return mSystemGestures; + } + private int getDisplayId() { return mDisplayContent.getDisplayId(); } @@ -1455,8 +1475,7 @@ public class DisplayPolicy { } void onDisplayInfoChanged(DisplayInfo info) { - mSystemGestures.screenWidth = info.logicalWidth; - mSystemGestures.screenHeight = info.logicalHeight; + getSystemGestures().onDisplayInfoChanged(info); } private void layoutStatusBar(DisplayFrames displayFrames, Rect contentFrame) { @@ -1969,7 +1988,7 @@ public class DisplayPolicy { public void onOverlayChangedLw() { updateCurrentUserResources(); onConfigurationChanged(); - mSystemGestures.onConfigurationChanged(); + getSystemGestures().onConfigurationChanged(); } /** @@ -2040,10 +2059,10 @@ public class DisplayPolicy { } mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode); - mLeftGestureInset = mGestureNavigationSettingsObserver.getLeftSensitivity(res); - mRightGestureInset = mGestureNavigationSettingsObserver.getRightSensitivity(res); - mNavButtonForcedVisible = - mGestureNavigationSettingsObserver.areNavigationButtonForcedVisible(); + final GestureNavigationSettingsObserver observer = getGestureNavigationSettingsObserver(); + mLeftGestureInset = observer.getLeftSensitivity(res); + mRightGestureInset = observer.getRightSensitivity(res); + mNavButtonForcedVisible = observer.areNavigationButtonForcedVisible(); mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough); mNavigationBarAlwaysShowOnSideGesture = res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture); @@ -3056,7 +3075,7 @@ public class DisplayPolicy { } void release() { - mHandler.post(mGestureNavigationSettingsObserver::unregister); + mHandler.post(getGestureNavigationSettingsObserver()::unregister); } @VisibleForTesting diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index 75176df6aaf7..a971794dc97d 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -124,7 +124,8 @@ class InsetsStateController { ? provider.getSource().getType() : ITYPE_INVALID; return getInsetsForTarget(type, target.getWindowingMode(), target.isAlwaysOnTop(), target.getFrozenInsetsState() != null ? target.getFrozenInsetsState() : - target.mAboveInsetsState); + (target.mAttrs.receiveInsetsIgnoringZOrder ? mState : + target.mAboveInsetsState)); } InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) { diff --git a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java index f3859b41b6fd..a98a47802914 100644 --- a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java +++ b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java @@ -126,11 +126,17 @@ class SystemGesturesPointerEventListener implements PointerEventListener { Slog.w(TAG, "Cannot create GestureDetector, display removed:" + displayId); return; } + onDisplayInfoChanged(info); mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), mHandler) { }; }); } + void onDisplayInfoChanged(DisplayInfo info) { + screenWidth = info.logicalWidth; + screenHeight = info.logicalHeight; + } + @Override public void onPointerEvent(MotionEvent event) { if (mGestureDetector != null && event.isTouchEvent()) { diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index f3b69e30b40a..0be43ab8d26c 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -180,6 +180,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } else if (launchMode == WINDOWING_MODE_FULLSCREEN) { if (DEBUG) appendLog("activity-options-fullscreen=" + outParams.mBounds); } else if (layout != null && canApplyFreeformPolicy) { + mTmpBounds.set(currentParams.mBounds); getLayoutBounds(display, root, layout, mTmpBounds); if (!mTmpBounds.isEmpty()) { launchMode = WINDOWING_MODE_FREEFORM; @@ -500,11 +501,11 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } private void getLayoutBounds(@NonNull DisplayContent display, @NonNull ActivityRecord root, - @NonNull ActivityInfo.WindowLayout windowLayout, @NonNull Rect outBounds) { + @NonNull ActivityInfo.WindowLayout windowLayout, @NonNull Rect inOutBounds) { final int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK; final int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; if (!windowLayout.hasSpecifiedSize() && verticalGravity == 0 && horizontalGravity == 0) { - outBounds.setEmpty(); + inOutBounds.setEmpty(); return; } @@ -518,11 +519,17 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { int width; int height; if (!windowLayout.hasSpecifiedSize()) { - outBounds.setEmpty(); - getTaskBounds(root, display, windowLayout, WINDOWING_MODE_FREEFORM, - /* hasInitialBounds */ false, outBounds); - width = outBounds.width(); - height = outBounds.height(); + if (!inOutBounds.isEmpty()) { + // If the bounds is resolved already and WindowLayout doesn't have any opinion on + // its size, use the already resolved size and apply the gravity to it. + width = inOutBounds.width(); + height = inOutBounds.height(); + } else { + getTaskBounds(root, display, windowLayout, WINDOWING_MODE_FREEFORM, + /* hasInitialBounds */ false, inOutBounds); + width = inOutBounds.width(); + height = inOutBounds.height(); + } } else { width = defaultWidth; if (windowLayout.width > 0 && windowLayout.width < defaultWidth) { @@ -563,11 +570,11 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { fractionOfVerticalOffset = 0.5f; } - outBounds.set(0, 0, width, height); - outBounds.offset(displayStableBounds.left, displayStableBounds.top); + inOutBounds.set(0, 0, width, height); + inOutBounds.offset(displayStableBounds.left, displayStableBounds.top); final int xOffset = (int) (fractionOfHorizontalOffset * (defaultWidth - width)); final int yOffset = (int) (fractionOfVerticalOffset * (defaultHeight - height)); - outBounds.offset(xOffset, yOffset); + inOutBounds.offset(xOffset, yOffset); } private boolean shouldLaunchUnresizableAppInFreeform(ActivityRecord activity, diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java index 18184b0a82af..f1d8e6c167d7 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java @@ -592,6 +592,7 @@ public class LocalDisplayAdapterTest { new DisplayModeDirector.RefreshRateRange(60f, 60f), new DisplayModeDirector.RefreshRateRange(60f, 60f) )); + waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); verify(mSurfaceControlProxy).setDesiredDisplayModeSpecs(display.token, new SurfaceControl.DesiredDisplayModeSpecs( /* baseModeId */ 0, diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java new file mode 100644 index 000000000000..170f561aa2da --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java @@ -0,0 +1,581 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.accessibility; + + +import static android.view.accessibility.AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; +import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS; +import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS; +import static android.view.accessibility.AccessibilityNodeInfo.ROOT_NODE_ID; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.app.Instrumentation; +import android.content.Context; +import android.os.RemoteException; +import android.view.AccessibilityInteractionController; +import android.view.View; +import android.view.ViewRootImpl; +import android.view.WindowManager; +import android.view.accessibility.AccessibilityNodeIdManager; +import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.AccessibilityNodeProvider; +import android.view.accessibility.IAccessibilityInteractionConnectionCallback; +import android.widget.FrameLayout; +import android.widget.TextView; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + +/** + * Tests that verify expected node and prefetched node results when finding a view by node id. We + * send some requests to the controller via View methods to control message timing. + */ +@RunWith(AndroidJUnit4.class) +public class AccessibilityInteractionControllerNodeRequestsTest { + private AccessibilityInteractionController mAccessibilityInteractionController; + @Mock + private IAccessibilityInteractionConnectionCallback mMockClientCallback1; + @Mock + private IAccessibilityInteractionConnectionCallback mMockClientCallback2; + + @Captor + private ArgumentCaptor<AccessibilityNodeInfo> mFindInfoCaptor; + @Captor private ArgumentCaptor<List<AccessibilityNodeInfo>> mPrefetchInfoListCaptor; + + private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation(); + private static final int MOCK_CLIENT_1_THREAD_AND_PROCESS_ID = 1; + private static final int MOCK_CLIENT_2_THREAD_AND_PROCESS_ID = 2; + + private static final String FRAME_LAYOUT_DESCRIPTION = "frameLayout"; + private static final String TEXT_VIEW_1_DESCRIPTION = "textView1"; + private static final String TEXT_VIEW_2_DESCRIPTION = "textView2"; + + private TestFrameLayout mFrameLayout; + private TestTextView mTextView1; + private TestTextView2 mTextView2; + + private boolean mSendClient1RequestForTextAfterTextPrefetched; + private boolean mSendClient2RequestForTextAfterTextPrefetched; + private boolean mSendRequestForTextAndIncludeUnImportantViews; + private int mMockClient1InteractionId; + private int mMockClient2InteractionId; + + @Before + public void setUp() throws Throwable { + MockitoAnnotations.initMocks(this); + + mInstrumentation.runOnMainSync(() -> { + final Context context = mInstrumentation.getTargetContext(); + final ViewRootImpl viewRootImpl = new ViewRootImpl(context, context.getDisplay()); + + mFrameLayout = new TestFrameLayout(context); + mTextView1 = new TestTextView(context); + mTextView2 = new TestTextView2(context); + + mFrameLayout.addView(mTextView1); + mFrameLayout.addView(mTextView2); + + // The controller retrieves views through this manager, and registration happens on + // when attached to a window, which we don't have. We can simply reference FrameLayout + // with ROOT_NODE_ID + AccessibilityNodeIdManager.getInstance().registerViewWithId( + mTextView1, mTextView1.getAccessibilityViewId()); + AccessibilityNodeIdManager.getInstance().registerViewWithId( + mTextView2, mTextView2.getAccessibilityViewId()); + + try { + viewRootImpl.setView(mFrameLayout, new WindowManager.LayoutParams(), null); + + } catch (WindowManager.BadTokenException e) { + // activity isn't running, we will ignore BadTokenException. + } + + mAccessibilityInteractionController = + new AccessibilityInteractionController(viewRootImpl); + }); + + } + + @After + public void tearDown() throws Throwable { + AccessibilityNodeIdManager.getInstance().unregisterViewWithId( + mTextView1.getAccessibilityViewId()); + AccessibilityNodeIdManager.getInstance().unregisterViewWithId( + mTextView2.getAccessibilityViewId()); + } + + /** + * Tests a basic request for the root node with prefetch flag + * {@link AccessibilityNodeInfo#FLAG_PREFETCH_DESCENDANTS} + * + * @throws RemoteException + */ + @Test + public void testFindRootView_withOneClient_shouldReturnRootNodeAndPrefetchDescendants() + throws RemoteException { + // Request for our FrameLayout + sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1, + mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS); + mInstrumentation.waitForIdleSync(); + + // Verify we get FrameLayout + verify(mMockClientCallback1).setFindAccessibilityNodeInfoResult( + mFindInfoCaptor.capture(), eq(mMockClient1InteractionId)); + AccessibilityNodeInfo infoSentToService = mFindInfoCaptor.getValue(); + assertEquals(FRAME_LAYOUT_DESCRIPTION, infoSentToService.getContentDescription()); + + verify(mMockClientCallback1).setPrefetchAccessibilityNodeInfoResult( + mPrefetchInfoListCaptor.capture(), eq(mMockClient1InteractionId)); + // The descendants are our two TextViews + List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue(); + assertEquals(2, prefetchedNodes.size()); + assertEquals(TEXT_VIEW_1_DESCRIPTION, prefetchedNodes.get(0).getContentDescription()); + assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNodes.get(1).getContentDescription()); + + } + + /** + * Tests a basic request for TestTextView1's node with prefetch flag + * {@link AccessibilityNodeInfo#FLAG_PREFETCH_SIBLINGS} + * + * @throws RemoteException + */ + @Test + public void testFindTextView_withOneClient_shouldReturnNodeAndPrefetchedSiblings() + throws RemoteException { + // Request for TextView1 + sendNodeRequestToController(AccessibilityNodeInfo.makeNodeId( + mTextView1.getAccessibilityViewId(), AccessibilityNodeProvider.HOST_VIEW_ID), + mMockClientCallback1, mMockClient1InteractionId, FLAG_PREFETCH_SIBLINGS); + mInstrumentation.waitForIdleSync(); + + // Verify we get TextView1 + verify(mMockClientCallback1).setFindAccessibilityNodeInfoResult( + mFindInfoCaptor.capture(), eq(mMockClient1InteractionId)); + AccessibilityNodeInfo infoSentToService = mFindInfoCaptor.getValue(); + assertEquals(TEXT_VIEW_1_DESCRIPTION, infoSentToService.getContentDescription()); + + // Verify the prefetched sibling of TextView1 is TextView2 + verify(mMockClientCallback1).setPrefetchAccessibilityNodeInfoResult( + mPrefetchInfoListCaptor.capture(), eq(mMockClient1InteractionId)); + // TextView2 is the prefetched sibling + List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue(); + assertEquals(1, prefetchedNodes.size()); + assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNodes.get(0).getContentDescription()); + } + + /** + * Tests a series of controller requests to prevent prefetching. + * Request 1: Client 1 requests the root node + * Request 2: When the root node is initialized in + * {@link TestFrameLayout#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}, + * Client 2 requests TestTextView1's node + * + * Request 2 on the queue prevents prefetching for Request 1. + * + * @throws RemoteException + */ + @Test + public void testFindRootAndTextNodes_withTwoClients_shouldPreventClient1Prefetch() + throws RemoteException { + mFrameLayout.setAccessibilityDelegate(new View.AccessibilityDelegate() { + @Override + public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(host, info); + final long nodeId = AccessibilityNodeInfo.makeNodeId( + mTextView1.getAccessibilityViewId(), + AccessibilityNodeProvider.HOST_VIEW_ID); + + // Enqueue a request when this node is found from a different service for + // TextView1 + sendNodeRequestToController(nodeId, mMockClientCallback2, + mMockClient2InteractionId, FLAG_PREFETCH_SIBLINGS); + } + }); + // Client 1 request for FrameLayout + sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1, + mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS); + + mInstrumentation.waitForIdleSync(); + + // Verify client 1 gets FrameLayout + verify(mMockClientCallback1).setFindAccessibilityNodeInfoResult( + mFindInfoCaptor.capture(), eq(mMockClient1InteractionId)); + AccessibilityNodeInfo infoSentToService = mFindInfoCaptor.getValue(); + assertEquals(FRAME_LAYOUT_DESCRIPTION, infoSentToService.getContentDescription()); + + // The second request is put in the queue in the FrameLayout's onInitializeA11yNodeInfo, + // meaning prefetching is interrupted and does not even begin for the first request + verify(mMockClientCallback1, never()) + .setPrefetchAccessibilityNodeInfoResult(anyList(), anyInt()); + + // Verify client 2 gets TextView1 + verify(mMockClientCallback2).setFindAccessibilityNodeInfoResult( + mFindInfoCaptor.capture(), eq(mMockClient2InteractionId)); + infoSentToService = mFindInfoCaptor.getValue(); + assertEquals(TEXT_VIEW_1_DESCRIPTION, infoSentToService.getContentDescription()); + + // Verify the prefetched sibling of TextView1 is TextView2 (FLAG_PREFETCH_SIBLINGS) + verify(mMockClientCallback2).setPrefetchAccessibilityNodeInfoResult( + mPrefetchInfoListCaptor.capture(), eq(mMockClient2InteractionId)); + List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue(); + assertEquals(1, prefetchedNodes.size()); + assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNodes.get(0).getContentDescription()); + } + + /** + * Tests a series of controller same-service requests to interrupt prefetching and satisfy a + * pending node request. + * Request 1: Request the root node + * Request 2: When TextTextView1's node is initialized as part of Request 1's prefetching, + * request TestTextView1's node + * + * Request 1 prefetches TestTextView1's node, is interrupted by a pending request, and checks + * if its prefetched nodes satisfy any pending requests. It satisfies Request 2's request for + * TestTextView1's node. Request 2 is fulfilled, so it is removed from queue and does not + * prefetch. + * + * @throws RemoteException + */ + @Test + public void testFindRootAndTextNode_withOneClient_shouldInterruptPrefetchAndSatisfyPendingMsg() + throws RemoteException { + mSendClient1RequestForTextAfterTextPrefetched = true; + + mTextView1.setAccessibilityDelegate(new View.AccessibilityDelegate(){ + @Override + public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(host, info); + info.setContentDescription(TEXT_VIEW_1_DESCRIPTION); + final long nodeId = AccessibilityNodeInfo.makeNodeId( + mTextView1.getAccessibilityViewId(), + AccessibilityNodeProvider.HOST_VIEW_ID); + + if (mSendClient1RequestForTextAfterTextPrefetched) { + // Prevent a loop when processing second request + mSendClient1RequestForTextAfterTextPrefetched = false; + // TextView1 is prefetched here after the FrameLayout is found. Now enqueue a + // same-client request for TextView1 + sendNodeRequestToController(nodeId, mMockClientCallback1, + ++mMockClient1InteractionId, FLAG_PREFETCH_SIBLINGS); + + } + } + }); + // Client 1 requests FrameLayout + sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1, + mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS); + + // Flush out all messages + mInstrumentation.waitForIdleSync(); + + // When TextView1 is prefetched for FrameLayout, we put a message on the queue in + // TextView1's onInitializeA11yNodeInfo that requests for TextView1. The service thus get + // two node results for FrameLayout and TextView1. + verify(mMockClientCallback1, times(2)) + .setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(), anyInt()); + + List<AccessibilityNodeInfo> foundNodes = mFindInfoCaptor.getAllValues(); + assertEquals(FRAME_LAYOUT_DESCRIPTION, foundNodes.get(0).getContentDescription()); + assertEquals(TEXT_VIEW_1_DESCRIPTION, foundNodes.get(1).getContentDescription()); + + // The controller will look at FrameLayout's prefetched nodes and find matching nodes in + // pending requests. The prefetched TextView1 matches the second request. The second + // request was removed from queue and prefetching for this request never occurred. + verify(mMockClientCallback1, times(1)) + .setPrefetchAccessibilityNodeInfoResult(mPrefetchInfoListCaptor.capture(), + eq(mMockClient1InteractionId - 1)); + List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue(); + assertEquals(1, prefetchedNodes.size()); + assertEquals(TEXT_VIEW_1_DESCRIPTION, prefetchedNodes.get(0).getContentDescription()); + } + + /** + * Like above, but tests a series of controller requests from different services to interrupt + * prefetching and satisfy a pending node request. + * + * @throws RemoteException + */ + @Test + public void testFindRootAndTextNode_withTwoClients_shouldInterruptPrefetchAndSatisfyPendingMsg() + throws RemoteException { + mSendClient2RequestForTextAfterTextPrefetched = true; + mTextView1.setAccessibilityDelegate(new View.AccessibilityDelegate(){ + @Override + public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(host, info); + info.setContentDescription(TEXT_VIEW_1_DESCRIPTION); + final long nodeId = AccessibilityNodeInfo.makeNodeId( + mTextView1.getAccessibilityViewId(), + AccessibilityNodeProvider.HOST_VIEW_ID); + + if (mSendClient2RequestForTextAfterTextPrefetched) { + mSendClient2RequestForTextAfterTextPrefetched = false; + // TextView1 is prefetched here. Now enqueue client 2's request for + // TextView1 + sendNodeRequestToController(nodeId, mMockClientCallback2, + mMockClient2InteractionId, FLAG_PREFETCH_SIBLINGS); + } + } + }); + // Client 1 requests FrameLayout + sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1, + mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS); + + mInstrumentation.waitForIdleSync(); + + // Verify client 1 gets FrameLayout + verify(mMockClientCallback1, times(1)) + .setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(), anyInt()); + assertEquals(FRAME_LAYOUT_DESCRIPTION, + mFindInfoCaptor.getValue().getContentDescription()); + + // Verify client 1 has prefetched nodes + verify(mMockClientCallback1, times(1)) + .setPrefetchAccessibilityNodeInfoResult(mPrefetchInfoListCaptor.capture(), + eq(mMockClient1InteractionId)); + + // Verify client 1's only prefetched node is TextView1 + List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue(); + assertEquals(1, prefetchedNodes.size()); + assertEquals(TEXT_VIEW_1_DESCRIPTION, prefetchedNodes.get(0).getContentDescription()); + + // Verify client 2 gets TextView1 + verify(mMockClientCallback2, times(1)) + .setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(), anyInt()); + + assertEquals(TEXT_VIEW_1_DESCRIPTION, mFindInfoCaptor.getValue().getContentDescription()); + + // The second request was removed from queue and prefetching for this client request never + // occurred as it was satisfied. + verify(mMockClientCallback2, never()) + .setPrefetchAccessibilityNodeInfoResult(anyList(), anyInt()); + + } + + @Test + public void testFindNodeById_withTwoDifferentPrefetchFlags_shouldNotSatisfyPendingRequest() + throws RemoteException { + mSendRequestForTextAndIncludeUnImportantViews = true; + mTextView1.setAccessibilityDelegate(new View.AccessibilityDelegate(){ + @Override + public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(host, info); + info.setContentDescription(TEXT_VIEW_1_DESCRIPTION); + final long nodeId = AccessibilityNodeInfo.makeNodeId( + mTextView1.getAccessibilityViewId(), + AccessibilityNodeProvider.HOST_VIEW_ID); + + if (mSendRequestForTextAndIncludeUnImportantViews) { + mSendRequestForTextAndIncludeUnImportantViews = false; + // TextView1 is prefetched here for client 1. Now enqueue a request from a + // different client that holds different fetch flags for TextView1 + sendNodeRequestToController(nodeId, mMockClientCallback2, + mMockClient2InteractionId, + FLAG_PREFETCH_SIBLINGS | FLAG_INCLUDE_NOT_IMPORTANT_VIEWS); + } + } + }); + + // Mockito does not make copies of objects when called. It holds references, so + // the captor would point to client 2's results after all requests are processed. Verify + // prefetched node immediately + doAnswer(invocation -> { + List<AccessibilityNodeInfo> prefetched = invocation.getArgument(0); + assertEquals(TEXT_VIEW_1_DESCRIPTION, prefetched.get(0).getContentDescription()); + return null; + }).when(mMockClientCallback1).setPrefetchAccessibilityNodeInfoResult(anyList(), + eq(mMockClient1InteractionId)); + + // Client 1 requests FrameLayout + sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1, + mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS); + + mInstrumentation.waitForIdleSync(); + + // Verify client 1 gets FrameLayout + verify(mMockClientCallback1, times(1)) + .setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(), + eq(mMockClient1InteractionId)); + + assertEquals(FRAME_LAYOUT_DESCRIPTION, + mFindInfoCaptor.getValue().getContentDescription()); + + // Verify client 1 has prefetched results. The only prefetched node is TextView1 + // (from above doAnswer) + verify(mMockClientCallback1, times(1)) + .setPrefetchAccessibilityNodeInfoResult(mPrefetchInfoListCaptor.capture(), + eq(mMockClient1InteractionId)); + + // Verify client 2 gets TextView1 + verify(mMockClientCallback2, times(1)) + .setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(), + eq(mMockClient2InteractionId)); + assertEquals(TEXT_VIEW_1_DESCRIPTION, + mFindInfoCaptor.getValue().getContentDescription()); + // Verify client 2 has TextView2 as a prefetched node + verify(mMockClientCallback2, times(1)) + .setPrefetchAccessibilityNodeInfoResult(mPrefetchInfoListCaptor.capture(), + eq(mMockClient2InteractionId)); + List<AccessibilityNodeInfo> prefetchedNode = mPrefetchInfoListCaptor.getValue(); + assertEquals(1, prefetchedNode.size()); + assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNode.get(0).getContentDescription()); + } + + private void sendNodeRequestToController(long requestedNodeId, + IAccessibilityInteractionConnectionCallback callback, int interactionId, + int prefetchFlags) { + final int processAndThreadId = callback == mMockClientCallback1 + ? MOCK_CLIENT_1_THREAD_AND_PROCESS_ID + : MOCK_CLIENT_2_THREAD_AND_PROCESS_ID; + + mAccessibilityInteractionController.findAccessibilityNodeInfoByAccessibilityIdClientThread( + requestedNodeId, + null, interactionId, + callback, prefetchFlags, + processAndThreadId, + processAndThreadId, null, null); + + } + + private class TestFrameLayout extends FrameLayout { + + TestFrameLayout(Context context) { + super(context); + } + + @Override + public int getWindowVisibility() { + // We aren't attached to a window so let's pretend + return VISIBLE; + } + + @Override + public boolean isShown() { + // Controller check + return true; + } + + @Override + public int getAccessibilityViewId() { + // static id doesn't reset after tests so return the same one + return 0; + } + + @Override + public void addChildrenForAccessibility(ArrayList<View> outChildren) { + // ViewGroup#addChildrenForAccessbility sorting logic will switch these two + outChildren.add(mTextView1); + outChildren.add(mTextView2); + } + + @Override + public boolean includeForAccessibility() { + return true; + } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setContentDescription(FRAME_LAYOUT_DESCRIPTION); + } + } + + private class TestTextView extends TextView { + TestTextView(Context context) { + super(context); + } + + @Override + public int getWindowVisibility() { + return VISIBLE; + } + + @Override + public boolean isShown() { + return true; + } + + @Override + public int getAccessibilityViewId() { + return 1; + } + + @Override + public boolean includeForAccessibility() { + return true; + } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setContentDescription(TEXT_VIEW_1_DESCRIPTION); + } + } + + private class TestTextView2 extends TextView { + TestTextView2(Context context) { + super(context); + } + + @Override + public int getWindowVisibility() { + return VISIBLE; + } + + @Override + public boolean isShown() { + return true; + } + + @Override + public int getAccessibilityViewId() { + return 2; + } + + @Override + public boolean includeForAccessibility() { + return true; + } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setContentDescription(TEXT_VIEW_2_DESCRIPTION); + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java index 8b0e948579fb..b6b6932c4a93 100644 --- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java @@ -602,12 +602,12 @@ public class CompatConfigTest { .addEnableSinceSdkChangeWithId(2, 2L) .build(); compatConfig.forceNonDebuggableFinalForTest(true); - compatConfig.initOverrides(overridesFile); + compatConfig.initOverrides(overridesFile, new File("")); when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt())) .thenReturn(ApplicationInfoBuilder.create() - .withPackageName("foo.bar") - .debuggable() - .build()); + .withPackageName("foo.bar") + .debuggable() + .build()); when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt())) .thenThrow(new NameNotFoundException()); @@ -649,7 +649,7 @@ public class CompatConfigTest { .addEnableSinceSdkChangeWithId(2, 2L) .build(); compatConfig.forceNonDebuggableFinalForTest(true); - compatConfig.initOverrides(overridesFile); + compatConfig.initOverrides(overridesFile, new File("")); compatConfig.addOverrides(new CompatibilityOverrideConfig(Collections.singletonMap(1L, new PackageOverride.Builder() @@ -673,11 +673,11 @@ public class CompatConfigTest { } @Test - public void testLoadOverridesRaw() throws Exception { + public void testInitOverridesRaw() throws Exception { File tempDir = createTempDir(); File overridesFile = new File(tempDir, "overrides.xml"); // Change 1 is enabled for foo.bar (validated) - // Change 2 is disabled for bar.baz (deferred) + // Change 2 is disabled for bar.baz (raw) String xmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<overrides>\n" + " <change-overrides changeId=\"1\">\n" @@ -709,7 +709,7 @@ public class CompatConfigTest { .addEnableSinceSdkChangeWithId(2, 2L) .build(); compatConfig.forceNonDebuggableFinalForTest(true); - compatConfig.initOverrides(overridesFile); + compatConfig.initOverrides(overridesFile, new File("")); ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() .withPackageName("foo.bar") .withVersionCode(100L) @@ -728,7 +728,7 @@ public class CompatConfigTest { } @Test - public void testLoadOverridesDeferred() throws Exception { + public void testInitOverridesDeferred() throws Exception { File tempDir = createTempDir(); File overridesFile = new File(tempDir, "overrides.xml"); // Change 1 is enabled for foo.bar (validated) @@ -754,7 +754,7 @@ public class CompatConfigTest { .addEnableSinceSdkChangeWithId(2, 2L) .build(); compatConfig.forceNonDebuggableFinalForTest(true); - compatConfig.initOverrides(overridesFile); + compatConfig.initOverrides(overridesFile, new File("")); ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() .withPackageName("foo.bar") .debuggable() @@ -767,4 +767,115 @@ public class CompatConfigTest { assertThat(compatConfig.isChangeEnabled(1L, applicationInfo)).isTrue(); assertThat(compatConfig.willChangeBeEnabled(2L, "bar.baz")).isFalse(); } + + @Test + public void testInitOverridesWithStaticFile() throws Exception { + File tempDir = createTempDir(); + File dynamicOverridesFile = new File(tempDir, "dynamic_overrides.xml"); + File staticOverridesFile = new File(tempDir, "static_overrides.xml"); + // Change 1 is enabled for foo.bar (raw) + // Change 2 is disabled for bar.baz (raw) + String dynamicXmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + + "<overrides>" + + "<change-overrides changeId=\"1\">" + + "<raw>" + + " <raw-override-value packageName=\"foo.bar\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n" + + " </raw-override-value>\n" + + "</raw>" + + "</change-overrides>" + + "<change-overrides changeId=\"2\">" + + "<raw>" + + " <raw-override-value packageName=\"bar.baz\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"false\">\n" + + " </raw-override-value>\n" + + "</raw>" + + "</change-overrides>" + + "</overrides>"; + writeToFile(tempDir, "dynamic_overrides.xml", dynamicXmlData); + // Change 2 is enabled for foo.bar and bar.baz (raw) + // Change 3 is enabled for bar.baz (raw) + String staticXmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + + "<overrides>" + + "<change-overrides changeId=\"2\">" + + "<raw>" + + " <raw-override-value packageName=\"foo.bar\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n" + + " </raw-override-value>\n" + + " <raw-override-value packageName=\"bar.baz\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n" + + " </raw-override-value>\n" + + "</raw>" + + "</change-overrides>" + + "<change-overrides changeId=\"3\">" + + "<raw>" + + " <raw-override-value packageName=\"bar.baz\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n" + + " </raw-override-value>\n" + + "</raw>" + + "</change-overrides>" + + "</overrides>"; + writeToFile(tempDir, "static_overrides.xml", staticXmlData); + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledChangeWithId(1L) + .addDisabledChangeWithId(2L) + .addDisabledChangeWithId(3L) + .build(); + compatConfig.forceNonDebuggableFinalForTest(true); + // Adding an override that will be cleared after initOverrides is called. + compatConfig.addOverride(1L, "bar.baz", true); + compatConfig.initOverrides(dynamicOverridesFile, staticOverridesFile); + when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt())) + .thenThrow(new NameNotFoundException()); + when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt())) + .thenThrow(new NameNotFoundException()); + + assertThat(compatConfig.willChangeBeEnabled(1L, "foo.bar")).isTrue(); + assertThat(compatConfig.willChangeBeEnabled(2L, "foo.bar")).isTrue(); + assertThat(compatConfig.willChangeBeEnabled(2L, "bar.baz")).isFalse(); + assertThat(compatConfig.willChangeBeEnabled(3L, "bar.baz")).isTrue(); + assertThat(readFile(dynamicOverridesFile)) + .isEqualTo("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + + "<overrides>\n" + + " <change-overrides changeId=\"1\">\n" + + " <validated>\n" + + " </validated>\n" + + " <raw>\n" + + " <raw-override-value packageName=\"foo.bar\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n" + + " </raw-override-value>\n" + + " </raw>\n" + + " </change-overrides>\n" + + " <change-overrides changeId=\"2\">\n" + + " <validated>\n" + + " </validated>\n" + + " <raw>\n" + + " <raw-override-value packageName=\"foo.bar\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n" + + " </raw-override-value>\n" + + " <raw-override-value packageName=\"bar.baz\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"false\">\n" + + " </raw-override-value>\n" + + " </raw>\n" + + " </change-overrides>\n" + + " <change-overrides changeId=\"3\">\n" + + " <validated>\n" + + " </validated>\n" + + " <raw>\n" + + " <raw-override-value packageName=\"bar.baz\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n" + + " </raw-override-value>\n" + + " </raw>\n" + + " </change-overrides>\n" + + "</overrides>\n"); + } } diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java index 26a549d77664..a97ea268b1c8 100644 --- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java @@ -274,6 +274,87 @@ public final class DeviceStateManagerServiceTest { } @Test + public void requestState_pendingStateAtRequest() throws RemoteException { + TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback(); + mService.getBinderService().registerCallback(callback); + + mPolicy.blockConfigure(); + + final IBinder firstRequestToken = new Binder(); + final IBinder secondRequestToken = new Binder(); + assertEquals(callback.getLastNotifiedStatus(firstRequestToken), + TestDeviceStateManagerCallback.STATUS_UNKNOWN); + assertEquals(callback.getLastNotifiedStatus(secondRequestToken), + TestDeviceStateManagerCallback.STATUS_UNKNOWN); + + mService.getBinderService().requestState(firstRequestToken, + OTHER_DEVICE_STATE.getIdentifier(), 0 /* flags */); + + assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE); + assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), + OTHER_DEVICE_STATE.getIdentifier()); + + mService.getBinderService().requestState(secondRequestToken, + DEFAULT_DEVICE_STATE.getIdentifier(), 0 /* flags */); + + mPolicy.resumeConfigureOnce(); + + // First request status is now suspended as there is another pending request. + assertEquals(callback.getLastNotifiedStatus(firstRequestToken), + TestDeviceStateManagerCallback.STATUS_SUSPENDED); + // Second request status still unknown because the service is still awaiting policy + // callback. + assertEquals(callback.getLastNotifiedStatus(secondRequestToken), + TestDeviceStateManagerCallback.STATUS_UNKNOWN); + + assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE); + assertEquals(mService.getPendingState().get(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), + DEFAULT_DEVICE_STATE.getIdentifier()); + + mPolicy.resumeConfigure(); + + assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getPendingState(), Optional.empty()); + assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), + DEFAULT_DEVICE_STATE.getIdentifier()); + + // Now cancel the second request to make the first request active. + mService.getBinderService().cancelRequest(secondRequestToken); + + assertEquals(callback.getLastNotifiedStatus(firstRequestToken), + TestDeviceStateManagerCallback.STATUS_ACTIVE); + assertEquals(callback.getLastNotifiedStatus(secondRequestToken), + TestDeviceStateManagerCallback.STATUS_CANCELED); + + assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE); + assertEquals(mService.getPendingState(), Optional.empty()); + assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), + OTHER_DEVICE_STATE.getIdentifier()); + } + + @Test + public void requestState_sameAsBaseState() throws RemoteException { + TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback(); + mService.getBinderService().registerCallback(callback); + + final IBinder token = new Binder(); + assertEquals(callback.getLastNotifiedStatus(token), + TestDeviceStateManagerCallback.STATUS_UNKNOWN); + + mService.getBinderService().requestState(token, DEFAULT_DEVICE_STATE.getIdentifier(), + 0 /* flags */); + + assertEquals(callback.getLastNotifiedStatus(token), + TestDeviceStateManagerCallback.STATUS_ACTIVE); + } + + @Test public void requestState_flagCancelWhenBaseChanges() throws RemoteException { TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback(); mService.getBinderService().registerCallback(callback); @@ -407,6 +488,14 @@ public final class DeviceStateManagerServiceTest { } } + public void resumeConfigureOnce() { + if (mPendingConfigureCompleteRunnable != null) { + Runnable onComplete = mPendingConfigureCompleteRunnable; + mPendingConfigureCompleteRunnable = null; + onComplete.run(); + } + } + public int getMostRecentRequestedStateToConfigure() { return mLastDeviceStateRequestedToConfigure; } diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java index 81b2381cd629..15ada896512b 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java @@ -88,6 +88,7 @@ public class DisplayModeDirectorTest { private static final String TAG = "DisplayModeDirectorTest"; private static final boolean DEBUG = false; private static final float FLOAT_TOLERANCE = 0.01f; + private static final int DISPLAY_ID = 0; private Context mContext; private FakesInjector mInjector; @@ -107,19 +108,29 @@ public class DisplayModeDirectorTest { private DisplayModeDirector createDirectorFromRefreshRateArray( float[] refreshRates, int baseModeId) { + return createDirectorFromRefreshRateArray(refreshRates, baseModeId, refreshRates[0]); + } + + private DisplayModeDirector createDirectorFromRefreshRateArray( + float[] refreshRates, int baseModeId, float defaultRefreshRate) { DisplayModeDirector director = new DisplayModeDirector(mContext, mHandler, mInjector); - int displayId = 0; Display.Mode[] modes = new Display.Mode[refreshRates.length]; + Display.Mode defaultMode = null; for (int i = 0; i < refreshRates.length; i++) { modes[i] = new Display.Mode( /*modeId=*/baseModeId + i, /*width=*/1000, /*height=*/1000, refreshRates[i]); + if (refreshRates[i] == defaultRefreshRate) { + defaultMode = modes[i]; + } } + assertThat(defaultMode).isNotNull(); + SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>(); - supportedModesByDisplay.put(displayId, modes); + supportedModesByDisplay.put(DISPLAY_ID, modes); director.injectSupportedModesByDisplay(supportedModesByDisplay); SparseArray<Display.Mode> defaultModesByDisplay = new SparseArray<>(); - defaultModesByDisplay.put(displayId, modes[0]); + defaultModesByDisplay.put(DISPLAY_ID, defaultMode); director.injectDefaultModeByDisplay(defaultModesByDisplay); return director; } @@ -130,16 +141,15 @@ public class DisplayModeDirectorTest { for (int i = 0; i < numRefreshRates; i++) { refreshRates[i] = minFps + i; } - return createDirectorFromRefreshRateArray(refreshRates, /*baseModeId=*/minFps); + return createDirectorFromRefreshRateArray(refreshRates, /*baseModeId=*/minFps, + /*defaultRefreshRate=*/minFps); } @Test public void testDisplayModeVoting() { - int displayId = 0; - // With no votes present, DisplayModeDirector should allow any refresh rate. DesiredDisplayModeSpecs modeSpecs = - createDirectorFromFpsRange(60, 90).getDesiredDisplayModeSpecs(displayId); + createDirectorFromFpsRange(60, 90).getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(modeSpecs.baseModeId).isEqualTo(60); assertThat(modeSpecs.primaryRefreshRateRange.min).isEqualTo(0f); assertThat(modeSpecs.primaryRefreshRateRange.max).isEqualTo(Float.POSITIVE_INFINITY); @@ -156,12 +166,12 @@ public class DisplayModeDirectorTest { assertTrue(2 * numPriorities < maxFps - minFps + 1); SparseArray<Vote> votes = new SparseArray<>(); SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>(); - votesByDisplay.put(displayId, votes); + votesByDisplay.put(DISPLAY_ID, votes); for (int i = 0; i < numPriorities; i++) { int priority = Vote.MIN_PRIORITY + i; votes.put(priority, Vote.forRefreshRates(minFps + i, maxFps - i)); director.injectVotesByDisplay(votesByDisplay); - modeSpecs = director.getDesiredDisplayModeSpecs(displayId); + modeSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(modeSpecs.baseModeId).isEqualTo(minFps + i); assertThat(modeSpecs.primaryRefreshRateRange.min) .isEqualTo((float) (minFps + i)); @@ -177,11 +187,11 @@ public class DisplayModeDirectorTest { DisplayModeDirector director = createDirectorFromFpsRange(60, 90); SparseArray<Vote> votes = new SparseArray<>(); SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>(); - votesByDisplay.put(displayId, votes); + votesByDisplay.put(DISPLAY_ID, votes); votes.put(Vote.MAX_PRIORITY, Vote.forRefreshRates(65, 85)); votes.put(Vote.MIN_PRIORITY, Vote.forRefreshRates(70, 80)); director.injectVotesByDisplay(votesByDisplay); - modeSpecs = director.getDesiredDisplayModeSpecs(displayId); + modeSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(modeSpecs.baseModeId).isEqualTo(70); assertThat(modeSpecs.primaryRefreshRateRange.min).isEqualTo(70f); assertThat(modeSpecs.primaryRefreshRateRange.max).isEqualTo(80f); @@ -190,18 +200,17 @@ public class DisplayModeDirectorTest { @Test public void testVotingWithFloatingPointErrors() { - int displayId = 0; DisplayModeDirector director = createDirectorFromFpsRange(50, 90); SparseArray<Vote> votes = new SparseArray<>(); SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>(); - votesByDisplay.put(displayId, votes); + votesByDisplay.put(DISPLAY_ID, votes); float error = FLOAT_TOLERANCE / 4; votes.put(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, Vote.forRefreshRates(0, 60)); votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forRefreshRates(60 + error, 60 + error)); votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60 - error, 60 - error)); director.injectVotesByDisplay(votesByDisplay); - DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60); assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60); @@ -213,15 +222,14 @@ public class DisplayModeDirectorTest { assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_REFRESH_RATE); assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_SIZE); - int displayId = 0; DisplayModeDirector director = createDirectorFromFpsRange(60, 90); SparseArray<Vote> votes = new SparseArray<>(); SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>(); - votesByDisplay.put(displayId, votes); + votesByDisplay.put(DISPLAY_ID, votes); votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90)); votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60)); director.injectVotesByDisplay(votesByDisplay); - DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60); assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60); @@ -229,7 +237,7 @@ public class DisplayModeDirectorTest { votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90)); votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90)); director.injectVotesByDisplay(votesByDisplay); - desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90); assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90); @@ -237,7 +245,7 @@ public class DisplayModeDirectorTest { votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90)); votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60)); director.injectVotesByDisplay(votesByDisplay); - desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90); assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90); @@ -245,7 +253,7 @@ public class DisplayModeDirectorTest { votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 60)); votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90)); director.injectVotesByDisplay(votesByDisplay); - desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60); assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60); } @@ -261,14 +269,13 @@ public class DisplayModeDirectorTest { assertTrue(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE >= Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF); - int displayId = 0; DisplayModeDirector director = createDirectorFromFpsRange(60, 90); SparseArray<Vote> votes = new SparseArray<>(); SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>(); - votesByDisplay.put(displayId, votes); + votesByDisplay.put(DISPLAY_ID, votes); votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60)); director.injectVotesByDisplay(votesByDisplay); - DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60); assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60); assertThat(desiredSpecs.appRequestRefreshRateRange.min).isAtMost(60f); @@ -277,7 +284,7 @@ public class DisplayModeDirectorTest { votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE, Vote.forRefreshRates(90, Float.POSITIVE_INFINITY)); director.injectVotesByDisplay(votesByDisplay); - desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90); assertThat(desiredSpecs.primaryRefreshRateRange.max).isAtLeast(90f); assertThat(desiredSpecs.appRequestRefreshRateRange.min).isAtMost(60f); @@ -285,7 +292,7 @@ public class DisplayModeDirectorTest { votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(75, 75)); director.injectVotesByDisplay(votesByDisplay); - desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(75); assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(75); assertThat(desiredSpecs.appRequestRefreshRateRange.min) @@ -355,11 +362,10 @@ public class DisplayModeDirectorTest { @Test public void testVotingWithAlwaysRespectAppRequest() { - final int displayId = 0; DisplayModeDirector director = createDirectorFromFpsRange(50, 90); SparseArray<Vote> votes = new SparseArray<>(); SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>(); - votesByDisplay.put(displayId, votes); + votesByDisplay.put(DISPLAY_ID, votes); votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(0, 60)); votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE, Vote.forRefreshRates(60, 90)); votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90)); @@ -369,7 +375,7 @@ public class DisplayModeDirectorTest { director.injectVotesByDisplay(votesByDisplay); assertThat(director.shouldAlwaysRespectAppRequestedMode()).isFalse(); - DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60); assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60); @@ -377,7 +383,7 @@ public class DisplayModeDirectorTest { director.setShouldAlwaysRespectAppRequestedMode(true); assertThat(director.shouldAlwaysRespectAppRequestedMode()).isTrue(); - desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90); assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90); assertThat(desiredSpecs.baseModeId).isEqualTo(90); @@ -385,7 +391,7 @@ public class DisplayModeDirectorTest { director.setShouldAlwaysRespectAppRequestedMode(false); assertThat(director.shouldAlwaysRespectAppRequestedMode()).isFalse(); - desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60); assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60); assertThat(desiredSpecs.baseModeId).isEqualTo(60); @@ -393,11 +399,10 @@ public class DisplayModeDirectorTest { @Test public void testVotingWithSwitchingTypeNone() { - final int displayId = 0; DisplayModeDirector director = createDirectorFromFpsRange(0, 90); SparseArray<Vote> votes = new SparseArray<>(); SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>(); - votesByDisplay.put(displayId, votes); + votesByDisplay.put(DISPLAY_ID, votes); votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE, Vote.forRefreshRates(30, 90)); votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRefreshRates(0, 60)); @@ -405,7 +410,7 @@ public class DisplayModeDirectorTest { director.injectVotesByDisplay(votesByDisplay); assertThat(director.getModeSwitchingType()) .isNotEqualTo(DisplayManager.SWITCHING_TYPE_NONE); - DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(30); assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60); @@ -417,7 +422,7 @@ public class DisplayModeDirectorTest { assertThat(director.getModeSwitchingType()) .isEqualTo(DisplayManager.SWITCHING_TYPE_NONE); - desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(30); assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(30); assertThat(desiredSpecs.appRequestRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(30); @@ -427,29 +432,38 @@ public class DisplayModeDirectorTest { @Test public void testVotingWithSwitchingTypeWithinGroups() { - final int displayId = 0; DisplayModeDirector director = createDirectorFromFpsRange(0, 90); director.setModeSwitchingType(DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS); assertThat(director.getModeSwitchingType()) .isEqualTo(DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS); - DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(desiredSpecs.allowGroupSwitching).isFalse(); } @Test public void testVotingWithSwitchingTypeWithinAndAcrossGroups() { - final int displayId = 0; DisplayModeDirector director = createDirectorFromFpsRange(0, 90); director.setModeSwitchingType(DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS); assertThat(director.getModeSwitchingType()) .isEqualTo(DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS); - DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); assertThat(desiredSpecs.allowGroupSwitching).isTrue(); } @Test + public void testDefaultDisplayModeIsSelectedIfAvailable() { + final float[] refreshRates = new float[]{24f, 25f, 30f, 60f, 90f}; + final int defaultModeId = 3; + DisplayModeDirector director = createDirectorFromRefreshRateArray( + refreshRates, /*baseModeId=*/0, refreshRates[defaultModeId]); + + DesiredDisplayModeSpecs specs = director.getDesiredDisplayModeSpecs(DISPLAY_ID); + assertThat(specs.baseModeId).isEqualTo(defaultModeId); + } + + @Test public void testBrightnessObserverGetsUpdatedRefreshRatesForZone() { DisplayModeDirector director = createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0); diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/FontCrashDetectorTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/FontCrashDetectorTest.java deleted file mode 100644 index 275e7c7fec04..000000000000 --- a/services/tests/servicestests/src/com/android/server/graphics/fonts/FontCrashDetectorTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.graphics.fonts; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.Context; -import android.os.FileUtils; -import android.platform.test.annotations.Presubmit; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.io.File; - -@Presubmit -@SmallTest -@RunWith(AndroidJUnit4.class) -public final class FontCrashDetectorTest { - - private File mCacheDir; - - @SuppressWarnings("ResultOfMethodCallIgnored") - @Before - public void setUp() { - Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); - mCacheDir = new File(context.getCacheDir(), "UpdatableFontDirTest"); - FileUtils.deleteContentsAndDir(mCacheDir); - mCacheDir.mkdirs(); - } - - @Test - public void detectCrash() throws Exception { - // Prepare a marker file. - File file = new File(mCacheDir, "detectCrash"); - assertThat(file.createNewFile()).isTrue(); - - FontCrashDetector detector = new FontCrashDetector(file); - assertThat(detector.hasCrashed()).isTrue(); - - detector.clear(); - assertThat(detector.hasCrashed()).isFalse(); - assertThat(file.exists()).isFalse(); - } - - @Test - public void monitorCrash() { - File file = new File(mCacheDir, "monitorCrash"); - FontCrashDetector detector = new FontCrashDetector(file); - assertThat(detector.hasCrashed()).isFalse(); - - FontCrashDetector.MonitoredBlock block = detector.start(); - assertThat(file.exists()).isTrue(); - - block.close(); - assertThat(file.exists()).isFalse(); - } -} diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java index f2254a98a70e..c08857ca9bdc 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java @@ -74,8 +74,6 @@ public class ActiveSourceActionTest { when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager); when(mIPowerManagerMock.isInteractive()).thenReturn(true); - HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy); - mHdmiControlService = new HdmiControlService(mContextSpy) { @Override AudioManager getAudioManager() { @@ -106,15 +104,11 @@ public class ActiveSourceActionTest { protected void writeStringSystemProperty(String key, String value) { // do nothing } - - @Override - protected HdmiCecConfig getHdmiCecConfig() { - return hdmiCecConfig; - } }; Looper looper = mTestLooper.getLooper(); mHdmiControlService.setIoLooper(looper); + mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy)); mNativeWrapper = new FakeNativeWrapper(); HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper( this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter()); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java index 44418ce1e9c4..50ba761cef10 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java @@ -76,8 +76,6 @@ public class ArcInitiationActionFromAvrTest { when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager); when(mIPowerManagerMock.isInteractive()).thenReturn(true); - HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy); - HdmiControlService hdmiControlService = new HdmiControlService(mContextSpy) { @Override @@ -112,11 +110,6 @@ public class ArcInitiationActionFromAvrTest { Looper getServiceLooper() { return mTestLooper.getLooper(); } - - @Override - protected HdmiCecConfig getHdmiCecConfig() { - return hdmiCecConfig; - } }; mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(hdmiControlService) { @@ -128,6 +121,7 @@ public class ArcInitiationActionFromAvrTest { mHdmiCecLocalDeviceAudioSystem.init(); Looper looper = mTestLooper.getLooper(); hdmiControlService.setIoLooper(looper); + hdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy)); mNativeWrapper = new FakeNativeWrapper(); HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper( hdmiControlService, mNativeWrapper, hdmiControlService.getAtomWriter()); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java index d454d8771e15..aa5bc933002d 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java @@ -77,8 +77,6 @@ public class ArcTerminationActionFromAvrTest { when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager); when(mIPowerManagerMock.isInteractive()).thenReturn(true); - HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy); - HdmiControlService hdmiControlService = new HdmiControlService(mContextSpy) { @Override @@ -113,15 +111,11 @@ public class ArcTerminationActionFromAvrTest { Looper getServiceLooper() { return mTestLooper.getLooper(); } - - @Override - protected HdmiCecConfig getHdmiCecConfig() { - return hdmiCecConfig; - } }; Looper looper = mTestLooper.getLooper(); hdmiControlService.setIoLooper(looper); + hdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy)); mNativeWrapper = new FakeNativeWrapper(); HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper( hdmiControlService, mNativeWrapper, hdmiControlService.getAtomWriter()); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java index 7cb72c414e52..ef7b274eeb83 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java @@ -86,8 +86,6 @@ public class DevicePowerStatusActionTest { when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager); when(mIPowerManagerMock.isInteractive()).thenReturn(true); - HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy); - mHdmiControlService = new HdmiControlService(mContextSpy) { @Override AudioManager getAudioManager() { @@ -118,15 +116,11 @@ public class DevicePowerStatusActionTest { protected void writeStringSystemProperty(String key, String value) { // do nothing } - - @Override - protected HdmiCecConfig getHdmiCecConfig() { - return hdmiCecConfig; - } }; Looper looper = mTestLooper.getLooper(); mHdmiControlService.setIoLooper(looper); + mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy)); mNativeWrapper = new FakeNativeWrapper(); HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper( this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter()); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java index 9bf95c0edcdb..678f8b219e28 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java @@ -106,8 +106,6 @@ public class DeviceSelectActionTest { PowerManager powerManager = new PowerManager(context, mIPowerManagerMock, mIThermalServiceMock, new Handler(mMyLooper)); - HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context); - mHdmiControlService = new HdmiControlService(InstrumentationRegistry.getTargetContext()) { @Override @@ -133,16 +131,12 @@ public class DeviceSelectActionTest { protected PowerManager getPowerManager() { return powerManager; } - - @Override - protected HdmiCecConfig getHdmiCecConfig() { - return hdmiCecConfig; - } }; mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService); mHdmiCecLocalDeviceTv.init(); mHdmiControlService.setIoLooper(mMyLooper); + mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context)); mNativeWrapper = new FakeNativeWrapper(); mHdmiCecController = HdmiCecController.createWithNativeWrapper( mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter()); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java index eedbc958dcd5..6bb148d43a57 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java @@ -98,8 +98,6 @@ public class HdmiCecLocalDeviceAudioSystemTest { PowerManager powerManager = new PowerManager(context, mIPowerManagerMock, mIThermalServiceMock, new Handler(mMyLooper)); - HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context); - mHdmiControlService = new HdmiControlService(InstrumentationRegistry.getTargetContext()) { @Override @@ -188,17 +186,13 @@ public class HdmiCecLocalDeviceAudioSystemTest { protected PowerManager getPowerManager() { return powerManager; } - - @Override - protected HdmiCecConfig getHdmiCecConfig() { - return hdmiCecConfig; - } }; mHdmiControlService.getHdmiCecConfig().setIntValue( HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, HdmiControlManager.VOLUME_CONTROL_ENABLED); mMyLooper = mTestLooper.getLooper(); + mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context)); mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService); mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService) { @Override diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java index b11ac24b9a29..915392e6eb80 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java @@ -87,7 +87,6 @@ public class HdmiCecLocalDevicePlaybackTest { mMyLooper = mTestLooper.getLooper(); PowerManager powerManager = new PowerManager(context, mIPowerManagerMock, mIThermalServiceMock, new Handler(mMyLooper)); - HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context); mHdmiControlService = new HdmiControlService(InstrumentationRegistry.getTargetContext()) { @@ -136,15 +135,11 @@ public class HdmiCecLocalDevicePlaybackTest { protected PowerManager getPowerManager() { return powerManager; } - - @Override - protected HdmiCecConfig getHdmiCecConfig() { - return hdmiCecConfig; - } }; mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService); mHdmiCecLocalDevicePlayback.init(); + mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context)); mHdmiControlService.setIoLooper(mMyLooper); mNativeWrapper = new FakeNativeWrapper(); mHdmiCecController = HdmiCecController.createWithNativeWrapper( diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java index 0717112da12c..b3f008598dc8 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java @@ -128,8 +128,6 @@ public class HdmiCecLocalDeviceTest { Context context = InstrumentationRegistry.getTargetContext(); - HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context); - mHdmiControlService = new HdmiControlService(context) { @Override @@ -163,13 +161,9 @@ public class HdmiCecLocalDeviceTest { void wakeUp() { mWakeupMessageReceived = true; } - - @Override - protected HdmiCecConfig getHdmiCecConfig() { - return hdmiCecConfig; - } }; mHdmiControlService.setIoLooper(mTestLooper.getLooper()); + mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context)); mNativeWrapper = new FakeNativeWrapper(); mHdmiCecController = HdmiCecController.createWithNativeWrapper( mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter()); 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 4623eb5b7d4b..4b3ef2f2cfd1 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java @@ -81,8 +81,6 @@ public class HdmiCecLocalDeviceTvTest { PowerManager powerManager = new PowerManager(context, mIPowerManagerMock, mIThermalServiceMock, new Handler(mMyLooper)); - HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context); - mHdmiControlService = new HdmiControlService(InstrumentationRegistry.getTargetContext()) { @Override @@ -119,16 +117,12 @@ public class HdmiCecLocalDeviceTvTest { AudioManager getAudioManager() { return mAudioManager; } - - @Override - protected HdmiCecConfig getHdmiCecConfig() { - return hdmiCecConfig; - } }; mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService); mHdmiCecLocalDeviceTv.init(); mHdmiControlService.setIoLooper(mMyLooper); + mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context)); mNativeWrapper = new FakeNativeWrapper(); mHdmiCecController = HdmiCecController.createWithNativeWrapper( mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter()); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java index 06373c2284b2..1c7ff421fe92 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java @@ -62,12 +62,12 @@ public class HdmiCecPowerStatusControllerTest { private FakeNativeWrapper mNativeWrapper; private TestLooper mTestLooper = new TestLooper(); private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>(); - private int mHdmiCecVersion = HdmiControlManager.HDMI_CEC_VERSION_1_4_B; @Mock private IPowerManager mIPowerManagerMock; @Mock private IThermalService mIThermalServiceMock; private HdmiControlService mHdmiControlService; + private HdmiCecLocalDevicePlayback mHdmiCecLocalDevicePlayback; @Before public void setUp() throws Exception { @@ -81,8 +81,6 @@ public class HdmiCecPowerStatusControllerTest { when(contextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager); when(mIPowerManagerMock.isInteractive()).thenReturn(true); - HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(contextSpy); - mHdmiControlService = new HdmiControlService(contextSpy) { @Override boolean isControlEnabled() { @@ -100,33 +98,24 @@ public class HdmiCecPowerStatusControllerTest { } @Override - int getCecVersion() { - return mHdmiCecVersion; - } - - @Override boolean isPowerStandby() { return false; } - - @Override - protected HdmiCecConfig getHdmiCecConfig() { - return hdmiCecConfig; - } }; mHdmiControlService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY); - HdmiCecLocalDevicePlayback hdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback( + mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback( mHdmiControlService); - hdmiCecLocalDevicePlayback.init(); + mHdmiCecLocalDevicePlayback.init(); mHdmiControlService.setIoLooper(myLooper); + mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(contextSpy)); mNativeWrapper = new FakeNativeWrapper(); HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper( mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter()); mHdmiControlService.setCecController(hdmiCecController); mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService)); mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService)); - mLocalDevices.add(hdmiCecLocalDevicePlayback); + mLocalDevices.add(mHdmiCecLocalDevicePlayback); HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1]; hdmiPortInfos[0] = new HdmiPortInfo(1, HdmiPortInfo.PORT_OUTPUT, 0x0000, true, false, false); @@ -188,77 +177,84 @@ public class HdmiCecPowerStatusControllerTest { @Test public void setPowerStatus_doesntSendBroadcast_1_4() { + setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B); mHdmiCecPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_ON); mTestLooper.dispatchAll(); HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus( - Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST, + mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST, HdmiControlManager.POWER_STATUS_ON); assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus); } @Test public void setPowerStatus_transient_doesntSendBroadcast_1_4() { + setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B); mHdmiCecPowerStatusController.setPowerStatus( HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON); mTestLooper.dispatchAll(); HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus( - Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST, + mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST, HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON); assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus); } @Test public void setPowerStatus_fast_transient_doesntSendBroadcast_1_4() { + setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B); mHdmiCecPowerStatusController.setPowerStatus( HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON, false); mTestLooper.dispatchAll(); HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus( - Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST, + mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST, HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON); assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus); } @Test public void setPowerStatus_sendsBroadcast_2_0() { - mHdmiCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0; - + setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0); mHdmiCecPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_ON); mTestLooper.dispatchAll(); HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus( - Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST, + mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST, HdmiControlManager.POWER_STATUS_ON); assertThat(mNativeWrapper.getResultMessages()).contains(reportPowerStatus); } @Test public void setPowerStatus_transient_sendsBroadcast_2_0() { - mHdmiCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0; - + setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0); mHdmiCecPowerStatusController.setPowerStatus( HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON); mTestLooper.dispatchAll(); HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus( - Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST, + mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST, HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON); assertThat(mNativeWrapper.getResultMessages()).contains(reportPowerStatus); } @Test public void setPowerStatus_fast_transient_doesntSendBroadcast_2_0() { - mHdmiCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0; - + setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0); mHdmiCecPowerStatusController.setPowerStatus( HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON, false); mTestLooper.dispatchAll(); HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus( - Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST, + mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST, HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON); assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus); } + + private void setCecVersion(int version) { + mHdmiControlService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION, version); + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + mTestLooper.dispatchAll(); + } } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java index 32a70480c39e..47f3bf9daba7 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java @@ -19,6 +19,7 @@ import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM; import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_PLAYBACK; import static com.android.server.SystemService.PHASE_BOOT_COMPLETED; +import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY; import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC; import static com.google.common.truth.Truth.assertThat; @@ -44,12 +45,12 @@ import android.os.RemoteException; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; import android.provider.Settings; +import android.util.Log; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -68,14 +69,64 @@ import java.util.Optional; @RunWith(JUnit4.class) public class HdmiControlServiceTest { - private class HdmiCecLocalDeviceMyDevice extends HdmiCecLocalDeviceSource { + private class MockPlaybackDevice extends HdmiCecLocalDevicePlayback { private boolean mCanGoToStandby; private boolean mIsStandby; private boolean mIsDisabled; - protected HdmiCecLocalDeviceMyDevice(HdmiControlService service, int deviceType) { - super(service, deviceType); + MockPlaybackDevice(HdmiControlService service) { + super(service); + } + + @Override + protected void onAddressAllocated(int logicalAddress, int reason) {} + + @Override + protected int getPreferredAddress() { + return 0; + } + + @Override + protected void setPreferredAddress(int addr) {} + + @Override + protected boolean canGoToStandby() { + return mCanGoToStandby; + } + + @Override + protected void disableDevice( + boolean initiatedByCec, final PendingActionClearedCallback originalCallback) { + mIsDisabled = true; + originalCallback.onCleared(this); + } + + @Override + protected void onStandby(boolean initiatedByCec, int standbyAction) { + mIsStandby = true; + } + + protected boolean isStandby() { + return mIsStandby; + } + + protected boolean isDisabled() { + return mIsDisabled; + } + + protected void setCanGoToStandby(boolean canGoToStandby) { + mCanGoToStandby = canGoToStandby; + } + } + private class MockAudioSystemDevice extends HdmiCecLocalDeviceAudioSystem { + + private boolean mCanGoToStandby; + private boolean mIsStandby; + private boolean mIsDisabled; + + MockAudioSystemDevice(HdmiControlService service) { + super(service); } @Override @@ -123,8 +174,8 @@ public class HdmiControlServiceTest { private Context mContextSpy; private HdmiControlService mHdmiControlService; private HdmiCecController mHdmiCecController; - private HdmiCecLocalDeviceMyDevice mMyAudioSystemDevice; - private HdmiCecLocalDeviceMyDevice mMyPlaybackDevice; + private MockAudioSystemDevice mAudioSystemDevice; + private MockPlaybackDevice mPlaybackDevice; private FakeNativeWrapper mNativeWrapper; private Looper mMyLooper; private TestLooper mTestLooper = new TestLooper(); @@ -144,6 +195,7 @@ public class HdmiControlServiceTest { PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock, mIThermalServiceMock, null); when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager); + when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager); when(mIPowerManagerMock.isInteractive()).thenReturn(true); HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy); @@ -157,21 +209,17 @@ public class HdmiControlServiceTest { @Override protected void writeStringSystemProperty(String key, String value) { } - - @Override - protected HdmiCecConfig getHdmiCecConfig() { - return hdmiCecConfig; - } }; mMyLooper = mTestLooper.getLooper(); - mMyAudioSystemDevice = - new HdmiCecLocalDeviceMyDevice(mHdmiControlService, DEVICE_AUDIO_SYSTEM); - mMyPlaybackDevice = new HdmiCecLocalDeviceMyDevice(mHdmiControlService, DEVICE_PLAYBACK); - mMyAudioSystemDevice.init(); - mMyPlaybackDevice.init(); + mAudioSystemDevice = new MockAudioSystemDevice(mHdmiControlService); + mPlaybackDevice = new MockPlaybackDevice(mHdmiControlService); + mAudioSystemDevice.init(); + mPlaybackDevice.init(); mHdmiControlService.setIoLooper(mMyLooper); + mHdmiControlService.setHdmiCecConfig(hdmiCecConfig); + mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY); mNativeWrapper = new FakeNativeWrapper(); mHdmiCecController = HdmiCecController.createWithNativeWrapper( @@ -180,8 +228,8 @@ public class HdmiControlServiceTest { mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService)); mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService)); - mLocalDevices.add(mMyAudioSystemDevice); - mLocalDevices.add(mMyPlaybackDevice); + mLocalDevices.add(mAudioSystemDevice); + mLocalDevices.add(mPlaybackDevice); mHdmiPortInfo = new HdmiPortInfo[4]; mHdmiPortInfo[0] = new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x2100, true, false, false); @@ -192,6 +240,9 @@ public class HdmiControlServiceTest { mHdmiPortInfo[3] = new HdmiPortInfo(4, HdmiPortInfo.PORT_INPUT, 0x3000, true, false, false); mNativeWrapper.setPortInfo(mHdmiPortInfo); + mHdmiControlService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, + HdmiControlManager.HDMI_CEC_CONTROL_ENABLED); mHdmiControlService.initService(); mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); @@ -201,13 +252,13 @@ public class HdmiControlServiceTest { @Test public void onStandby_notByCec_cannotGoToStandby() { mStandbyMessageReceived = false; - mMyPlaybackDevice.setCanGoToStandby(false); + mPlaybackDevice.setCanGoToStandby(false); mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF); - assertTrue(mMyPlaybackDevice.isStandby()); - assertTrue(mMyAudioSystemDevice.isStandby()); - assertFalse(mMyPlaybackDevice.isDisabled()); - assertFalse(mMyAudioSystemDevice.isDisabled()); + assertTrue(mPlaybackDevice.isStandby()); + assertTrue(mAudioSystemDevice.isStandby()); + assertFalse(mPlaybackDevice.isDisabled()); + assertFalse(mAudioSystemDevice.isDisabled()); } @Test @@ -215,10 +266,10 @@ public class HdmiControlServiceTest { mStandbyMessageReceived = true; mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF); - assertTrue(mMyPlaybackDevice.isStandby()); - assertTrue(mMyAudioSystemDevice.isStandby()); - assertTrue(mMyPlaybackDevice.isDisabled()); - assertTrue(mMyAudioSystemDevice.isDisabled()); + assertTrue(mPlaybackDevice.isStandby()); + assertTrue(mAudioSystemDevice.isStandby()); + assertTrue(mPlaybackDevice.isDisabled()); + assertTrue(mAudioSystemDevice.isDisabled()); } @Test @@ -275,6 +326,7 @@ public class HdmiControlServiceTest { mHdmiControlService.getHdmiCecConfig().setIntValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION, HdmiControlManager.HDMI_CEC_VERSION_2_0); + mTestLooper.dispatchAll(); mHdmiControlService.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED); mNativeWrapper.clearResultMessages(); @@ -555,8 +607,8 @@ public class HdmiControlServiceTest { HdmiCecMessage reportFeatures = HdmiCecMessageBuilder.buildReportFeatures( Constants.ADDR_PLAYBACK_1, HdmiControlManager.HDMI_CEC_VERSION_2_0, Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM), - mMyPlaybackDevice.getRcProfile(), mMyPlaybackDevice.getRcFeatures(), - mMyPlaybackDevice.getDeviceFeatures()); + mPlaybackDevice.getRcProfile(), mPlaybackDevice.getRcFeatures(), + mPlaybackDevice.getDeviceFeatures()); assertThat(mNativeWrapper.getResultMessages()).contains(reportFeatures); } @@ -573,8 +625,8 @@ public class HdmiControlServiceTest { HdmiCecMessage reportFeatures = HdmiCecMessageBuilder.buildReportFeatures( Constants.ADDR_PLAYBACK_1, HdmiControlManager.HDMI_CEC_VERSION_2_0, Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM), - mMyPlaybackDevice.getRcProfile(), mMyPlaybackDevice.getRcFeatures(), - mMyPlaybackDevice.getDeviceFeatures()); + mPlaybackDevice.getRcProfile(), mPlaybackDevice.getRcFeatures(), + mPlaybackDevice.getDeviceFeatures()); assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportFeatures); } @@ -590,8 +642,8 @@ public class HdmiControlServiceTest { HdmiCecMessage reportFeatures = HdmiCecMessageBuilder.buildReportFeatures( Constants.ADDR_PLAYBACK_1, HdmiControlManager.HDMI_CEC_VERSION_2_0, Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM), - mMyPlaybackDevice.getRcProfile(), mMyPlaybackDevice.getRcFeatures(), - mMyPlaybackDevice.getDeviceFeatures()); + mPlaybackDevice.getRcProfile(), mPlaybackDevice.getRcFeatures(), + mPlaybackDevice.getDeviceFeatures()); assertThat(mNativeWrapper.getResultMessages()).contains(reportFeatures); } @@ -612,41 +664,42 @@ public class HdmiControlServiceTest { assertEquals(runnerUid, Binder.getCallingWorkSourceUid()); } - @Ignore("b/180499471") @Test public void initCecVersion_limitToMinimumSupportedVersion() { + mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B); + Log.e("MARVIN", "set setting CEC"); mHdmiControlService.getHdmiCecConfig().setIntValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION, HdmiControlManager.HDMI_CEC_VERSION_2_0); - mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B); - mHdmiControlService.initService(); + mTestLooper.dispatchAll(); assertThat(mHdmiControlService.getCecVersion()).isEqualTo( HdmiControlManager.HDMI_CEC_VERSION_1_4_B); } - @Ignore("b/180499471") @Test public void initCecVersion_limitToAtLeast1_4() { + Log.e("MARVIN", "set HAL CEC to 0"); + mNativeWrapper.setCecVersion(0x0); + Log.e("MARVIN", "set setting CEC to 2"); mHdmiControlService.getHdmiCecConfig().setIntValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION, HdmiControlManager.HDMI_CEC_VERSION_2_0); - mNativeWrapper.setCecVersion(0x0); - mHdmiControlService.initService(); + mTestLooper.dispatchAll(); assertThat(mHdmiControlService.getCecVersion()).isEqualTo( HdmiControlManager.HDMI_CEC_VERSION_1_4_B); } - @Ignore("b/180499471") @Test public void initCecVersion_useHighestMatchingVersion() { + mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0); + Log.e("MARVIN", "set setting CEC"); mHdmiControlService.getHdmiCecConfig().setIntValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION, HdmiControlManager.HDMI_CEC_VERSION_2_0); - mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0); - mHdmiControlService.initService(); + mTestLooper.dispatchAll(); assertThat(mHdmiControlService.getCecVersion()).isEqualTo( HdmiControlManager.HDMI_CEC_VERSION_2_0); } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java index b8dfd5672056..605f781b23df 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java @@ -84,8 +84,6 @@ public class PowerStatusMonitorActionTest { when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager); when(mIPowerManagerMock.isInteractive()).thenReturn(true); - HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy); - mHdmiControlService = new HdmiControlService(mContextSpy) { @Override AudioManager getAudioManager() { @@ -116,15 +114,11 @@ public class PowerStatusMonitorActionTest { protected void writeStringSystemProperty(String key, String value) { // do nothing } - - @Override - protected HdmiCecConfig getHdmiCecConfig() { - return hdmiCecConfig; - } }; Looper looper = mTestLooper.getLooper(); mHdmiControlService.setIoLooper(looper); + mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy)); mNativeWrapper = new FakeNativeWrapper(); HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper( this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter()); @@ -185,6 +179,7 @@ public class PowerStatusMonitorActionTest { mHdmiControlService.getHdmiCecConfig().setIntValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION, HdmiControlManager.HDMI_CEC_VERSION_2_0); + mTestLooper.dispatchAll(); sendMessageFromPlaybackDevice(ADDR_PLAYBACK_1, 0x1000); reportPowerStatus(ADDR_PLAYBACK_1, true, HdmiControlManager.POWER_STATUS_ON); mTestLooper.dispatchAll(); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java index f9160abcbfbf..e82c788020ed 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java @@ -65,8 +65,6 @@ public class SystemAudioInitiationActionFromAvrTest { Context context = InstrumentationRegistry.getTargetContext(); - HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context); - HdmiControlService hdmiControlService = new HdmiControlService(context) { @Override void sendCecCommand( @@ -164,15 +162,11 @@ public class SystemAudioInitiationActionFromAvrTest { int pathToPortId(int path) { return -1; } - - @Override - protected HdmiCecConfig getHdmiCecConfig() { - return hdmiCecConfig; - } }; Looper looper = mTestLooper.getLooper(); hdmiControlService.setIoLooper(looper); + hdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context)); HdmiCecController.NativeWrapper nativeWrapper = new FakeNativeWrapper(); HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper( hdmiControlService, nativeWrapper, hdmiControlService.getAtomWriter()); diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 74bf4f5da70d..13c3919cefc5 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -2041,7 +2041,8 @@ public class NetworkPolicyManagerServiceTest { final NetworkCapabilities networkCapabilities = new NetworkCapabilities(); networkCapabilities.addTransportType(TRANSPORT_WIFI); networkCapabilities.setSSID(TEST_SSID); - return new NetworkState(TYPE_WIFI, prop, networkCapabilities, null, null); + return new NetworkState(TYPE_WIFI, prop, networkCapabilities, new Network(TEST_NET_ID), + null); } private void expectHasInternetPermission(int uid, boolean hasIt) throws Exception { diff --git a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java index 8c62b7fe235e..3ca90603e9d2 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java @@ -91,6 +91,7 @@ public class InputDeviceDelegateTest { mInputDeviceDelegate = new InputDeviceDelegate( mContextSpy, new Handler(mTestLooper.getLooper())); + mInputDeviceDelegate.onSystemReady(); } @After @@ -99,6 +100,24 @@ public class InputDeviceDelegateTest { } @Test + public void beforeSystemReady_ignoresAnyUpdate() throws Exception { + when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[0]); + InputDeviceDelegate inputDeviceDelegate = new InputDeviceDelegate( + mContextSpy, new Handler(mTestLooper.getLooper())); + + inputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ true); + assertFalse(inputDeviceDelegate.isAvailable()); + + inputDeviceDelegate.onInputDeviceAdded(1); + assertFalse(inputDeviceDelegate.isAvailable()); + + updateInputDevices(new int[]{1}); + assertFalse(inputDeviceDelegate.isAvailable()); + + verify(mIInputManagerMock, never()).getInputDevice(anyInt()); + } + + @Test public void onInputDeviceAdded_withSettingsDisabled_ignoresNewDevice() throws Exception { when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[0]); mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ false); diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java index 1e6ef9137686..b6c11fe62ff6 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java @@ -88,6 +88,7 @@ public class VibrationScalerTest { mVibrationSettings = new VibrationSettings( mContextSpy, new Handler(mTestLooper.getLooper())); mVibrationScaler = new VibrationScaler(mContextSpy, mVibrationSettings); + mVibrationSettings.onSystemReady(); } @After diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java index d8679876965c..855012459bd6 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java @@ -106,6 +106,7 @@ public class VibrationSettingsTest { mAudioManager = mContextSpy.getSystemService(AudioManager.class); mVibrationSettings = new VibrationSettings(mContextSpy, new Handler(mTestLooper.getLooper())); + mVibrationSettings.onSystemReady(); setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0); setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0); @@ -162,6 +163,23 @@ public class VibrationSettingsTest { } @Test + public void shouldVibrateForRingerMode_beforeSystemReady_returnsFalseOnlyForRingtone() { + setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1); + setRingerMode(AudioManager.RINGER_MODE_MAX); + VibrationSettings vibrationSettings = new VibrationSettings(mContextSpy, + new Handler(mTestLooper.getLooper())); + + assertFalse(vibrationSettings.shouldVibrateForRingerMode( + VibrationAttributes.USAGE_RINGTONE)); + assertTrue(mVibrationSettings.shouldVibrateForRingerMode(VibrationAttributes.USAGE_ALARM)); + assertTrue(mVibrationSettings.shouldVibrateForRingerMode(VibrationAttributes.USAGE_TOUCH)); + assertTrue(mVibrationSettings.shouldVibrateForRingerMode( + VibrationAttributes.USAGE_NOTIFICATION)); + assertTrue(mVibrationSettings.shouldVibrateForRingerMode( + VibrationAttributes.USAGE_COMMUNICATION_REQUEST)); + } + + @Test public void shouldVibrateForRingerMode_withoutRingtoneUsage_returnsTrue() { assertTrue(mVibrationSettings.shouldVibrateForRingerMode(VibrationAttributes.USAGE_ALARM)); assertTrue(mVibrationSettings.shouldVibrateForRingerMode(VibrationAttributes.USAGE_TOUCH)); @@ -303,6 +321,37 @@ public class VibrationSettingsTest { } @Test + public void getDefaultIntensity_beforeSystemReady_returnsMediumToAllExceptAlarm() { + mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_HIGH); + mFakeVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_HIGH); + mFakeVibrator.setDefaultRingVibrationIntensity(Vibrator.VIBRATION_INTENSITY_HIGH); + + setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, + Vibrator.VIBRATION_INTENSITY_OFF); + setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, + Vibrator.VIBRATION_INTENSITY_OFF); + setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, + Vibrator.VIBRATION_INTENSITY_OFF); + + VibrationSettings vibrationSettings = new VibrationSettings(mContextSpy, + new Handler(mTestLooper.getLooper())); + + assertEquals(Vibrator.VIBRATION_INTENSITY_HIGH, + vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_ALARM)); + assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM, + vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_TOUCH)); + assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM, + vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION)); + assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM, + vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_UNKNOWN)); + assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM, + vibrationSettings.getDefaultIntensity( + VibrationAttributes.USAGE_PHYSICAL_EMULATION)); + assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM, + vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE)); + } + + @Test public void getDefaultIntensity_returnsIntensityFromVibratorService() { mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_HIGH); mFakeVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_MEDIUM); diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java index ba0a472c80dd..a28d18fb74d3 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java @@ -176,8 +176,14 @@ public class VibratorManagerServiceTest { LocalServices.removeServiceForTest(PowerManagerInternal.class); } + private VibratorManagerService createSystemReadyService() { + VibratorManagerService service = createService(); + service.systemReady(); + return service; + } + private VibratorManagerService createService() { - VibratorManagerService service = new VibratorManagerService( + return new VibratorManagerService( mContextSpy, new VibratorManagerService.Injector() { @Override @@ -201,8 +207,6 @@ public class VibratorManagerServiceTest { void addService(String name, IBinder service) { } }); - service.systemReady(); - return service; } @Test @@ -215,21 +219,44 @@ public class VibratorManagerServiceTest { } @Test + public void createService_doNotCrashIfUsedBeforeSystemReady() { + mockVibrators(1, 2); + mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL); + mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL); + VibratorManagerService service = createService(); + + assertNotNull(service.getVibratorIds()); + assertNotNull(service.getVibratorInfo(1)); + assertFalse(service.isVibrating(1)); + + CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced( + VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)); + vibrate(service, effect, HAPTIC_FEEDBACK_ATTRS); + service.cancelVibrate(service); + + assertTrue(service.setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS)); + + IVibratorStateListener listener = mockVibratorStateListener(); + assertTrue(service.registerVibratorStateListener(1, listener)); + assertTrue(service.unregisterVibratorStateListener(1, listener)); + } + + @Test public void getVibratorIds_withNullResultFromNative_returnsEmptyArray() { when(mNativeWrapperMock.getVibratorIds()).thenReturn(null); - assertArrayEquals(new int[0], createService().getVibratorIds()); + assertArrayEquals(new int[0], createSystemReadyService().getVibratorIds()); } @Test public void getVibratorIds_withNonEmptyResultFromNative_returnsSameArray() { mockVibrators(2, 1); - assertArrayEquals(new int[]{2, 1}, createService().getVibratorIds()); + assertArrayEquals(new int[]{2, 1}, createSystemReadyService().getVibratorIds()); } @Test public void getVibratorInfo_withMissingVibratorId_returnsNull() { mockVibrators(1); - assertNull(createService().getVibratorInfo(2)); + assertNull(createSystemReadyService().getVibratorInfo(2)); } @Test @@ -239,7 +266,7 @@ public class VibratorManagerServiceTest { vibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS, IVibrator.CAP_AMPLITUDE_CONTROL); vibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK); vibrator.setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK); - VibratorInfo info = createService().getVibratorInfo(1); + VibratorInfo info = createSystemReadyService().getVibratorInfo(1); assertNotNull(info); assertEquals(1, info.getId()); @@ -257,7 +284,7 @@ public class VibratorManagerServiceTest { @Test public void registerVibratorStateListener_callbacksAreTriggered() throws Exception { mockVibrators(1); - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); IVibratorStateListener listenerMock = mockVibratorStateListener(); service.registerVibratorStateListener(1, listenerMock); @@ -278,7 +305,7 @@ public class VibratorManagerServiceTest { @Test public void unregisterVibratorStateListener_callbackNotTriggeredAfter() throws Exception { mockVibrators(1); - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); IVibratorStateListener listenerMock = mockVibratorStateListener(); service.registerVibratorStateListener(1, listenerMock); @@ -303,7 +330,7 @@ public class VibratorManagerServiceTest { @Test public void registerVibratorStateListener_multipleVibratorsAreTriggered() throws Exception { mockVibrators(0, 1, 2); - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); IVibratorStateListener[] listeners = new IVibratorStateListener[3]; for (int i = 0; i < 3; i++) { listeners[i] = mockVibratorStateListener(); @@ -330,7 +357,8 @@ public class VibratorManagerServiceTest { CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced( VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)); - assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS)); + assertTrue(createSystemReadyService().setAlwaysOnEffect( + UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS)); VibrationEffect.Prebaked expectedEffect = new VibrationEffect.Prebaked( VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG); @@ -353,7 +381,8 @@ public class VibratorManagerServiceTest { .addVibrator(2, VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK)) .addVibrator(3, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)) .combine(); - assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS)); + assertTrue(createSystemReadyService().setAlwaysOnEffect( + UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS)); VibrationEffect.Prebaked expectedClick = new VibrationEffect.Prebaked( VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG); @@ -376,9 +405,11 @@ public class VibratorManagerServiceTest { CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced( VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)); - assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS)); + assertTrue(createSystemReadyService().setAlwaysOnEffect( + UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS)); - assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, null, ALARM_ATTRS)); + assertTrue(createSystemReadyService().setAlwaysOnEffect( + UID, PACKAGE_NAME, 1, null, ALARM_ATTRS)); assertNull(mVibratorProviders.get(1).getAlwaysOnEffect(1)); assertNull(mVibratorProviders.get(2).getAlwaysOnEffect(1)); @@ -392,7 +423,8 @@ public class VibratorManagerServiceTest { CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced( VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE)); - assertFalse(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS)); + assertFalse(createSystemReadyService().setAlwaysOnEffect( + UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS)); assertNull(mVibratorProviders.get(1).getAlwaysOnEffect(1)); } @@ -405,7 +437,8 @@ public class VibratorManagerServiceTest { CombinedVibrationEffect effect = CombinedVibrationEffect.startSequential() .addNext(0, VibrationEffect.get(VibrationEffect.EFFECT_CLICK)) .combine(); - assertFalse(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS)); + assertFalse(createSystemReadyService().setAlwaysOnEffect( + UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS)); assertNull(mVibratorProviders.get(1).getAlwaysOnEffect(1)); } @@ -413,7 +446,7 @@ public class VibratorManagerServiceTest { @Test public void setAlwaysOnEffect_withNoVibratorWithCapability_ignoresEffect() { mockVibrators(1); - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); CombinedVibrationEffect mono = CombinedVibrationEffect.createSynced( VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)); @@ -435,18 +468,18 @@ public class VibratorManagerServiceTest { setRingerMode(AudioManager.RINGER_MODE_NORMAL); setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0); setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0); - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); vibrate(service, VibrationEffect.createOneShot(40, 1), RINGTONE_ATTRS); setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0); setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 1); - service = createService(); + service = createSystemReadyService(); vibrate(service, VibrationEffect.createOneShot(40, 10), RINGTONE_ATTRS); assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1); setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0); - service = createService(); + service = createSystemReadyService(); vibrate(service, VibrationEffect.createOneShot(40, 100), RINGTONE_ATTRS); assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); @@ -459,7 +492,7 @@ public class VibratorManagerServiceTest { mockVibrators(1); FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1); fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE); vibrate(service, VibrationEffect.createOneShot(1, 1), HAPTIC_FEEDBACK_ATTRS); vibrate(service, VibrationEffect.createOneShot(2, 2), RINGTONE_ATTRS); @@ -480,7 +513,7 @@ public class VibratorManagerServiceTest { @Test public void vibrate_withAudioAttributes_usesOriginalAudioUsageInAppOpsManager() { - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); AudioAttributes audioAttributes = new AudioAttributes.Builder() @@ -496,7 +529,7 @@ public class VibratorManagerServiceTest { @Test public void vibrate_withVibrationAttributes_usesCorrespondingAudioUsageInAppOpsManager() { - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS); vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_TICK), NOTIFICATION_ATTRS); @@ -534,7 +567,7 @@ public class VibratorManagerServiceTest { when(mIInputManagerMock.getVibratorIds(eq(1))).thenReturn(new int[]{1}); when(mIInputManagerMock.getInputDevice(eq(1))).thenReturn(createInputDeviceWithVibrator(1)); setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1); - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced( VibrationEffect.createOneShot(10, 10)); @@ -550,7 +583,7 @@ public class VibratorManagerServiceTest { public void vibrate_withNativeCallbackTriggered_finishesVibration() throws Exception { mockVibrators(1); mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK); - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); // The native callback will be dispatched manually in this test. mTestLooper.stopAutoDispatchAndIgnoreExceptions(); @@ -573,7 +606,7 @@ public class VibratorManagerServiceTest { mockVibrators(1, 2); mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); // The native callback will be dispatched manually in this test. mTestLooper.stopAutoDispatchAndIgnoreExceptions(); @@ -619,7 +652,7 @@ public class VibratorManagerServiceTest { FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1); fakeVibrator1.setSupportedEffects(VibrationEffect.EFFECT_CLICK); mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced() .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK)) @@ -645,7 +678,7 @@ public class VibratorManagerServiceTest { mockVibrators(1, 2); FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1); fakeVibrator1.setSupportedEffects(VibrationEffect.EFFECT_CLICK); - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced() .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK)) @@ -665,7 +698,7 @@ public class VibratorManagerServiceTest { mockCapabilities(IVibratorManager.CAP_SYNC, IVibratorManager.CAP_PREPARE_ON); mockVibrators(1, 2); when(mNativeWrapperMock.prepareSynced(any())).thenReturn(false); - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced() .addVibrator(1, VibrationEffect.createOneShot(10, 50)) @@ -686,7 +719,7 @@ public class VibratorManagerServiceTest { mockVibrators(1, 2); when(mNativeWrapperMock.prepareSynced(eq(new int[]{1, 2}))).thenReturn(true); when(mNativeWrapperMock.triggerSynced(anyLong())).thenReturn(false); - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced() .addVibrator(1, VibrationEffect.createOneShot(10, 50)) @@ -716,7 +749,7 @@ public class VibratorManagerServiceTest { fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL, IVibrator.CAP_COMPOSE_EFFECTS); fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK); - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); vibrate(service, CombinedVibrationEffect.startSynced() .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK)) @@ -762,7 +795,7 @@ public class VibratorManagerServiceTest { @Test public void vibrate_withPowerModeChange_cancelVibrationIfNotAllowed() throws Exception { mockVibrators(1, 2); - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); vibrate(service, CombinedVibrationEffect.startSynced() .addVibrator(1, VibrationEffect.createOneShot(1000, 100)) @@ -780,7 +813,7 @@ public class VibratorManagerServiceTest { @Test public void vibrate_withSettingsChange_doNotCancelVibration() throws Exception { mockVibrators(1); - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); vibrate(service, VibrationEffect.createOneShot(1000, 100), HAPTIC_FEEDBACK_ATTRS); assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); @@ -793,7 +826,7 @@ public class VibratorManagerServiceTest { @Test public void cancelVibrate_stopsVibrating() throws Exception { mockVibrators(1); - VibratorManagerService service = createService(); + VibratorManagerService service = createSystemReadyService(); service.cancelVibrate(service); assertFalse(service.isVibrating(1)); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java index 47cf53b621d3..074ef3667857 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java @@ -323,4 +323,16 @@ public class DisplayPolicyTests extends WindowTestsBase { assertFalse(navBarSource.getFrame().isEmpty()); assertTrue(imeSource.getFrame().contains(navBarSource.getFrame())); } + + @UseTestDisplay + @Test + public void testDisplayPolicyNotCrash() { + final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy(); + + // Verify if modules initialized after DisplayContent ctr throws NPE. + displayPolicy.onDisplayInfoChanged(mDisplayInfo); + displayPolicy.onConfigurationChanged(); + displayPolicy.onOverlayChangedLw(); + displayPolicy.release(); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index be036034542e..80961d7afb70 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -416,6 +416,16 @@ public class InsetsStateControllerTest extends WindowTestsBase { verify(navBar, atLeastOnce()).notifyInsetsChanged(); } + @Test + public void testDispatchGlobalInsets() { + final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar"); + getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null); + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + assertNull(getController().getInsetsForWindow(app).peekSource(ITYPE_NAVIGATION_BAR)); + app.mAttrs.receiveInsetsIgnoringZOrder = true; + assertNotNull(getController().getInsetsForWindow(app).peekSource(ITYPE_NAVIGATION_BAR)); + } + private WindowState createTestWindow(String name) { final WindowState win = createWindow(null, TYPE_APPLICATION, name); win.setHasSurface(true); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java index a1e5afb8b758..fb2272ed9fd3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java @@ -521,6 +521,7 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { WINDOWING_MODE_FULLSCREEN); } + @Test public void testKeepsPictureInPictureLaunchModeInOptions() { final TestDisplayContent freeformDisplay = createNewDisplayContent( @@ -588,11 +589,14 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { } @Test - public void testNonEmptyLayoutInfersFreeformWithEmptySize() { + public void testLayoutWithGravityAndEmptySizeInfersFreeformAndRespectsCurrentSize() { final TestDisplayContent freeformDisplay = createNewDisplayContent( WINDOWING_MODE_FREEFORM); + final Rect expectedLaunchBounds = new Rect(0, 0, 200, 100); + mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea(); + mCurrent.mBounds.set(expectedLaunchBounds); final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder() .setGravity(Gravity.LEFT).build(); @@ -600,6 +604,9 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setLayout(layout).calculate()); + assertEquals(expectedLaunchBounds.width(), mResult.mBounds.width()); + assertEquals(expectedLaunchBounds.height(), mResult.mBounds.height()); + assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode, WINDOWING_MODE_FREEFORM); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index c13d6b19bf1d..ebc5c4ff280a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -538,9 +538,8 @@ class WindowTestsBase extends SystemServiceTestsBase { /** Creates a {@link DisplayContent} and adds it to the system. */ private DisplayContent createNewDisplay(DisplayInfo info, @DisplayImePolicy int imePolicy) { - final DisplayContent display = + final DisplayContent dc = new TestDisplayContent.Builder(mAtm, info).build(); - final DisplayContent dc = display.mDisplayContent; // this display can show IME. dc.mWmService.mDisplayWindowSettings.setDisplayImePolicy(dc, imePolicy); return dc; diff --git a/services/translation/java/com/android/server/translation/TranslationManagerService.java b/services/translation/java/com/android/server/translation/TranslationManagerService.java index 6aadd23d211f..b6244b8fb93b 100644 --- a/services/translation/java/com/android/server/translation/TranslationManagerService.java +++ b/services/translation/java/com/android/server/translation/TranslationManagerService.java @@ -20,19 +20,28 @@ import static android.Manifest.permission.MANAGE_UI_TRANSLATION; import static android.content.Context.TRANSLATION_MANAGER_SERVICE; import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_FAIL; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Binder; import android.os.RemoteException; +import android.os.ResultReceiver; +import android.os.ShellCallback; import android.util.Slog; import android.view.autofill.AutofillId; import android.view.translation.ITranslationManager; import android.view.translation.TranslationSpec; import android.view.translation.UiTranslationManager.UiTranslationState; +import com.android.internal.annotations.GuardedBy; import com.android.internal.os.IResultReceiver; import com.android.server.infra.AbstractMasterSystemService; import com.android.server.infra.FrameworkResourcesServiceNameResolver; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.List; /** @@ -48,6 +57,8 @@ public final class TranslationManagerService private static final String TAG = "TranslationManagerService"; + private static final int MAX_TEMP_SERVICE_SUBSTITUTION_DURATION_MS = 2 * 60_000; // 2 minutes + public TranslationManagerService(Context context) { // TODO: Discuss the disallow policy super(context, new FrameworkResourcesServiceNameResolver(context, @@ -60,19 +71,82 @@ public final class TranslationManagerService return new TranslationManagerServiceImpl(this, mLock, resolvedUserId, disabled); } + @Override + protected void enforceCallingPermissionForManagement() { + getContext().enforceCallingPermission(MANAGE_UI_TRANSLATION, TAG); + } + + @Override + protected int getMaximumTemporaryServiceDurationMs() { + return MAX_TEMP_SERVICE_SUBSTITUTION_DURATION_MS; + } + + @Override + protected void dumpLocked(String prefix, PrintWriter pw) { + super.dumpLocked(prefix, pw); + } + private void enforceCallerHasPermission(String permission) { final String msg = "Permission Denial from pid =" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + " doesn't hold " + permission; getContext().enforceCallingPermission(permission, msg); } + /** True if the currently set handler service is not overridden by the shell. */ + @GuardedBy("mLock") + private boolean isDefaultServiceLocked(int userId) { + final String defaultServiceName = mServiceNameResolver.getDefaultServiceName(userId); + if (defaultServiceName == null) { + return false; + } + + final String currentServiceName = mServiceNameResolver.getServiceName(userId); + return defaultServiceName.equals(currentServiceName); + } + + /** True if the caller of the api is the same app which hosts the TranslationService. */ + @GuardedBy("mLock") + private boolean isCalledByServiceAppLocked(int userId, @NonNull String methodName) { + final int callingUid = Binder.getCallingUid(); + + final String serviceName = mServiceNameResolver.getServiceName(userId); + if (serviceName == null) { + Slog.e(TAG, methodName + ": called by UID " + callingUid + + ", but there's no service set for user " + userId); + return false; + } + + final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName); + if (serviceComponent == null) { + Slog.w(TAG, methodName + ": invalid service name: " + serviceName); + return false; + } + + final String servicePackageName = serviceComponent.getPackageName(); + final PackageManager pm = getContext().getPackageManager(); + final int serviceUid; + try { + serviceUid = pm.getPackageUidAsUser(servicePackageName, userId); + } catch (PackageManager.NameNotFoundException e) { + Slog.w(TAG, methodName + ": could not verify UID for " + serviceName); + return false; + } + if (callingUid != serviceUid) { + Slog.e(TAG, methodName + ": called by UID " + callingUid + ", but service UID is " + + serviceUid); + return false; + } + return true; + } + final class TranslationManagerServiceStub extends ITranslationManager.Stub { @Override public void getSupportedLocales(IResultReceiver receiver, int userId) throws RemoteException { synchronized (mLock) { final TranslationManagerServiceImpl service = getServiceForUserLocked(userId); - if (service != null) { + if (service != null && (isDefaultServiceLocked(userId) + || isCalledByServiceAppLocked(userId, "getSupportedLocales"))) { service.getSupportedLocalesLocked(receiver); } else { Slog.v(TAG, "getSupportedLocales(): no service for " + userId); @@ -86,7 +160,8 @@ public final class TranslationManagerService int sessionId, IResultReceiver receiver, int userId) throws RemoteException { synchronized (mLock) { final TranslationManagerServiceImpl service = getServiceForUserLocked(userId); - if (service != null) { + if (service != null && (isDefaultServiceLocked(userId) + || isCalledByServiceAppLocked(userId, "onSessionCreated"))) { service.onSessionCreatedLocked(sourceSpec, destSpec, sessionId, receiver); } else { Slog.v(TAG, "onSessionCreated(): no service for " + userId); @@ -102,12 +177,35 @@ public final class TranslationManagerService enforceCallerHasPermission(MANAGE_UI_TRANSLATION); synchronized (mLock) { final TranslationManagerServiceImpl service = getServiceForUserLocked(userId); - if (service != null) { + if (service != null && (isDefaultServiceLocked(userId) + || isCalledByServiceAppLocked(userId, "updateUiTranslationState"))) { service.updateUiTranslationState(state, sourceSpec, destSpec, viewIds, taskId); } } } + + /** + * Dump the service state into the given stream. You run "adb shell dumpsys translation". + */ + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + synchronized (mLock) { + dumpLocked("", pw); + } + } + + @Override + public void onShellCommand(@Nullable FileDescriptor in, + @Nullable FileDescriptor out, + @Nullable FileDescriptor err, + @NonNull String[] args, + @Nullable ShellCallback callback, + @NonNull ResultReceiver resultReceiver) throws RemoteException { + new TranslationManagerServiceShellCommand( + TranslationManagerService.this).exec(this, in, out, err, args, callback, + resultReceiver); + } } @Override // from SystemService diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceShellCommand.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceShellCommand.java new file mode 100644 index 000000000000..ba1b3908a91e --- /dev/null +++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceShellCommand.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.translation; + +import android.os.ShellCommand; + +import java.io.PrintWriter; + +/** Handles adb shell commands send to TranslationManagerService. */ +public class TranslationManagerServiceShellCommand extends ShellCommand { + private final TranslationManagerService mService; + + TranslationManagerServiceShellCommand(TranslationManagerService service) { + mService = service; + } + + @Override + public int onCommand(String cmd) { + if (cmd == null) { + return handleDefaultCommands(cmd); + } + final PrintWriter pw = getOutPrintWriter(); + if ("set".equals(cmd)) { + return requestSet(pw); + } + return handleDefaultCommands(cmd); + } + + private int requestSet(PrintWriter pw) { + final String what = getNextArgRequired(); + if ("temporary-service".equals(what)) { + return setTemporaryService(pw); + } + pw.println("Invalid set: " + what); + return -1; + } + + private int setTemporaryService(PrintWriter pw) { + final int userId = Integer.parseInt(getNextArgRequired()); + final String serviceName = getNextArg(); + if (serviceName == null) { + mService.resetTemporaryService(userId); + return 0; + } + final int duration = Integer.parseInt(getNextArgRequired()); + mService.setTemporaryService(userId, serviceName, duration); + pw.println("TranslationService temporarily set to " + serviceName + " for " + + duration + "ms"); + return 0; + } + + @Override + public void onHelp() { + try (PrintWriter pw = getOutPrintWriter();) { + pw.println("Translation Service (translation) commands:"); + pw.println(" help"); + pw.println(" Prints this help text."); + pw.println(""); + pw.println(" set temporary-service USER_ID [COMPONENT_NAME DURATION]"); + pw.println(" Temporarily (for DURATION ms) changes the service implementation."); + pw.println(" To reset, call with just the USER_ID argument."); + pw.println(""); + } + } +} diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java index 706e3cb93a0f..a78f81331c8c 100644 --- a/telephony/java/android/telephony/NetworkRegistrationInfo.java +++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java @@ -371,6 +371,7 @@ public final class NetworkRegistrationInfo implements Parcelable { * Get the 5G NR connection state. * * @return the 5G NR connection state. + * @hide */ public @NRState int getNrState() { return mNrState; diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt index 386dafc590af..b61310aa4bd8 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt @@ -102,7 +102,7 @@ class OpenAppWarmTest(private val testSpec: FlickerTestParameter) { @Test fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible() - @Presubmit + @FlakyTest @Test fun visibleWindowsShownMoreThanOneConsecutiveEntry() = testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry() diff --git a/tests/UpdatableSystemFontTest/Android.bp b/tests/UpdatableSystemFontTest/Android.bp index ee24d48f0ed5..d4f1ad317d31 100644 --- a/tests/UpdatableSystemFontTest/Android.bp +++ b/tests/UpdatableSystemFontTest/Android.bp @@ -26,13 +26,9 @@ java_test_host { srcs: ["src/**/*.java"], libs: ["tradefed", "compatibility-tradefed", "compatibility-host-util"], static_libs: [ - "block_device_writer_jar", "frameworks-base-hostutils", ], test_suites: ["general-tests", "vts"], - target_required: [ - "block_device_writer_module", - ], data: [ ":NotoColorEmojiTtf", ":UpdatableSystemFontTestCertDer", diff --git a/tests/UpdatableSystemFontTest/AndroidTest.xml b/tests/UpdatableSystemFontTest/AndroidTest.xml index 7b919bd4b114..efe5d703880c 100644 --- a/tests/UpdatableSystemFontTest/AndroidTest.xml +++ b/tests/UpdatableSystemFontTest/AndroidTest.xml @@ -21,7 +21,6 @@ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> <option name="cleanup" value="true" /> - <option name="push" value="block_device_writer->/data/local/tmp/block_device_writer" /> <option name="push" value="UpdatableSystemFontTestCert.der->/data/local/tmp/UpdatableSystemFontTestCert.der" /> <option name="push" value="NotoColorEmoji.ttf->/data/local/tmp/NotoColorEmoji.ttf" /> <option name="push" value="UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig" /> diff --git a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java index e249f8a99b0c..92fa498f8326 100644 --- a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java +++ b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java @@ -21,7 +21,6 @@ import static com.google.common.truth.Truth.assertWithMessage; import android.platform.test.annotations.RootPermissionTest; -import com.android.blockdevicewriter.BlockDeviceWriter; import com.android.fsverity.AddFsVerityCertRule; import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.log.LogUtil.CLog; @@ -144,30 +143,6 @@ public class UpdatableSystemFontTest extends BaseHostJUnit4Test { assertThat(fontPathAfterReboot).isEqualTo(fontPath); } - @Test - public void reboot_clearDamagedFiles() throws Exception { - expectRemoteCommandToSucceed(String.format("cmd font update %s %s", - TEST_NOTO_COLOR_EMOJI_V1_TTF, TEST_NOTO_COLOR_EMOJI_V1_TTF_FSV_SIG)); - String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF); - assertThat(fontPath).startsWith("/data/fonts/files/"); - assertThat(BlockDeviceWriter.canReadByte(getDevice(), fontPath, 0)).isTrue(); - - BlockDeviceWriter.damageFileAgainstBlockDevice(getDevice(), fontPath, 0); - expectRemoteCommandToSucceed("stop"); - // We have to make sure system_server is gone before dropping caches, because system_server - // process holds font memory maps and prevents cache eviction. - waitUntilSystemServerIsGone(); - BlockDeviceWriter.assertFileNotOpen(getDevice(), fontPath); - BlockDeviceWriter.dropCaches(getDevice()); - assertThat(BlockDeviceWriter.canReadByte(getDevice(), fontPath, 0)).isFalse(); - - expectRemoteCommandToSucceed("start"); - waitUntilFontCommandIsReady(); - String fontPathAfterReboot = getFontPath(NOTO_COLOR_EMOJI_TTF); - assertWithMessage("Damaged file should be deleted") - .that(fontPathAfterReboot).startsWith("/system"); - } - private String getFontPath(String fontFileName) throws Exception { // TODO: add a dedicated command for testing. String lines = expectRemoteCommandToSucceed("cmd font dump"); diff --git a/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt b/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt index 56b56efd501b..0ca4d9551f39 100644 --- a/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt +++ b/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt @@ -63,10 +63,10 @@ class NetworkStateSnapshotTest { @Test fun testParcelUnparcel() { - val emptySnapshot = NetworkStateSnapshot(LinkProperties(), NetworkCapabilities(), - Network(TEST_NETID), null, TYPE_NONE) + val emptySnapshot = NetworkStateSnapshot(Network(TEST_NETID), NetworkCapabilities(), + LinkProperties(), null, TYPE_NONE) val snapshot = NetworkStateSnapshot( - TEST_LINK_PROPERTIES, TEST_CAPABILITIES, Network(TEST_NETID), TEST_IMSI, TYPE_WIFI) + Network(TEST_NETID), TEST_CAPABILITIES, TEST_LINK_PROPERTIES, TEST_IMSI, TYPE_WIFI) assertParcelSane(emptySnapshot, 5) assertParcelSane(snapshot, 5) } diff --git a/tests/net/common/java/android/net/UidRangeTest.java b/tests/net/common/java/android/net/UidRangeTest.java new file mode 100644 index 000000000000..1b1c95431d6f --- /dev/null +++ b/tests/net/common/java/android/net/UidRangeTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2016 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.net; + +import static android.os.UserHandle.MIN_SECONDARY_USER_ID; +import static android.os.UserHandle.SYSTEM; +import static android.os.UserHandle.USER_SYSTEM; +import static android.os.UserHandle.getUid; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.os.Build; +import android.os.UserHandle; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class UidRangeTest { + + /* + * UidRange is no longer passed to netd. UID ranges between the framework and netd are passed as + * UidRangeParcel objects. + */ + + @Rule + public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); + + @Test + public void testSingleItemUidRangeAllowed() { + new UidRange(123, 123); + new UidRange(0, 0); + new UidRange(Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + @Test + public void testNegativeUidsDisallowed() { + try { + new UidRange(-2, 100); + fail("Exception not thrown for negative start UID"); + } catch (IllegalArgumentException expected) { + } + + try { + new UidRange(-200, -100); + fail("Exception not thrown for negative stop UID"); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testStopLessThanStartDisallowed() { + final int x = 4195000; + try { + new UidRange(x, x - 1); + fail("Exception not thrown for negative-length UID range"); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testGetStartAndEndUser() throws Exception { + final UidRange uidRangeOfPrimaryUser = new UidRange( + getUid(USER_SYSTEM, 10000), getUid(USER_SYSTEM, 10100)); + final UidRange uidRangeOfSecondaryUser = new UidRange( + getUid(MIN_SECONDARY_USER_ID, 10000), getUid(MIN_SECONDARY_USER_ID, 10100)); + assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser()); + assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getEndUser()); + assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getStartUser()); + assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getEndUser()); + + final UidRange uidRangeForDifferentUsers = new UidRange( + getUid(USER_SYSTEM, 10000), getUid(MIN_SECONDARY_USER_ID, 10100)); + assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser()); + assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getEndUser()); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.R) + public void testCreateForUser() throws Exception { + final UidRange uidRangeOfPrimaryUser = UidRange.createForUser(SYSTEM); + final UidRange uidRangeOfSecondaryUser = UidRange.createForUser( + UserHandle.of(USER_SYSTEM + 1)); + assertTrue(uidRangeOfPrimaryUser.stop < uidRangeOfSecondaryUser.start); + assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser()); + assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getEndUser()); + assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getStartUser()); + assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getEndUser()); + } +} diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt index 9ed55f098a16..c10c573aa024 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt +++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt @@ -177,7 +177,7 @@ class ConnectivityServiceIntegrationTest { } private inner class TestConnectivityService(deps: Dependencies) : ConnectivityService( - context, netManager, statsService, dnsResolver, log, netd, deps) + context, statsService, dnsResolver, log, netd, deps) private fun makeDependencies(): ConnectivityService.Dependencies { val deps = spy(ConnectivityService.Dependencies()) diff --git a/tests/net/java/android/net/IpSecAlgorithmTest.java b/tests/net/java/android/net/IpSecAlgorithmTest.java index 2e1c29a2e405..3a8d6004f66f 100644 --- a/tests/net/java/android/net/IpSecAlgorithmTest.java +++ b/tests/net/java/android/net/IpSecAlgorithmTest.java @@ -129,6 +129,7 @@ public class IpSecAlgorithmTest { checkCryptKeyLenValidation(IpSecAlgorithm.CRYPT_AES_CTR, len); } checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_AES_XCBC, 128, 96); + checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_AES_CMAC, 128, 96); checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305, 288, 128); } diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt index 27224c216db3..64b774cc4340 100644 --- a/tests/net/java/android/net/NetworkTemplateTest.kt +++ b/tests/net/java/android/net/NetworkTemplateTest.kt @@ -20,14 +20,13 @@ import android.content.Context import android.net.ConnectivityManager.TYPE_MOBILE import android.net.ConnectivityManager.TYPE_WIFI import android.net.NetworkIdentity.SUBTYPE_COMBINED -import android.net.NetworkIdentity.OEM_NONE; -import android.net.NetworkIdentity.OEM_PAID; -import android.net.NetworkIdentity.OEM_PRIVATE; +import android.net.NetworkIdentity.OEM_NONE +import android.net.NetworkIdentity.OEM_PAID +import android.net.NetworkIdentity.OEM_PRIVATE import android.net.NetworkIdentity.buildNetworkIdentity import android.net.NetworkStats.DEFAULT_NETWORK_ALL import android.net.NetworkStats.METERED_ALL import android.net.NetworkStats.ROAMING_ALL -import android.net.NetworkTemplate.MATCH_ETHERNET import android.net.NetworkTemplate.MATCH_MOBILE import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD import android.net.NetworkTemplate.MATCH_WIFI @@ -50,7 +49,6 @@ import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertNotEquals import kotlin.test.assertTrue -import kotlin.test.fail private const val TEST_IMSI1 = "imsi1" private const val TEST_IMSI2 = "imsi2" @@ -60,17 +58,17 @@ private const val TEST_SSID1 = "ssid1" class NetworkTemplateTest { private val mockContext = mock(Context::class.java) - private fun buildMobileNetworkState(subscriberId: String): NetworkState = + private fun buildMobileNetworkState(subscriberId: String): NetworkStateSnapshot = buildNetworkState(TYPE_MOBILE, subscriberId = subscriberId) - private fun buildWifiNetworkState(ssid: String): NetworkState = + private fun buildWifiNetworkState(ssid: String): NetworkStateSnapshot = buildNetworkState(TYPE_WIFI, ssid = ssid) private fun buildNetworkState( type: Int, subscriberId: String? = null, ssid: String? = null, - oemManaged: Int = OEM_NONE, - ): NetworkState { + oemManaged: Int = OEM_NONE + ): NetworkStateSnapshot { val lp = LinkProperties() val caps = NetworkCapabilities().apply { setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false) @@ -81,7 +79,7 @@ class NetworkTemplateTest { setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, (oemManaged and OEM_PRIVATE) == OEM_PRIVATE) } - return NetworkState(type, lp, caps, mock(Network::class.java), subscriberId) + return NetworkStateSnapshot(mock(Network::class.java), caps, lp, subscriberId, type) } private fun NetworkTemplate.assertMatches(ident: NetworkIdentity) = @@ -179,7 +177,7 @@ class NetworkTemplateTest { OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE) // Verify that "not OEM managed network" constants are equal. - assertEquals(OEM_MANAGED_NO, OEM_NONE); + assertEquals(OEM_MANAGED_NO, OEM_NONE) // Verify the constants don't conflict. assertEquals(constantValues.size, constantValues.distinct().count()) @@ -201,8 +199,13 @@ class NetworkTemplateTest { * @param identSsid If networkType is {@code TYPE_WIFI}, this value must *NOT* be null. Provide * one of {@code TEST_SSID*}. */ - private fun matchOemManagedIdent(networkType: Int, matchType:Int, subscriberId: String? = null, - templateSsid: String? = null, identSsid: String? = null) { + private fun matchOemManagedIdent( + networkType: Int, + matchType: Int, + subscriberId: String? = null, + templateSsid: String? = null, + identSsid: String? = null + ) { val oemManagedStates = arrayOf(OEM_NONE, OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE) // A null subscriberId needs a null matchSubscriberIds argument as well. val matchSubscriberIds = if (subscriberId == null) null else arrayOf(subscriberId) diff --git a/tests/net/java/android/net/UidRangeTest.java b/tests/net/java/android/net/UidRangeTest.java deleted file mode 100644 index ea1df096e208..000000000000 --- a/tests/net/java/android/net/UidRangeTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2016 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.net; - -import static org.junit.Assert.fail; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class UidRangeTest { - - /* - * UidRange is no longer passed to netd. UID ranges between the framework and netd are passed as - * UidRangeParcel objects. - */ - - @Test - public void testSingleItemUidRangeAllowed() { - new UidRange(123, 123); - new UidRange(0, 0); - new UidRange(Integer.MAX_VALUE, Integer.MAX_VALUE); - } - - @Test - public void testNegativeUidsDisallowed() { - try { - new UidRange(-2, 100); - fail("Exception not thrown for negative start UID"); - } catch (IllegalArgumentException expected) { - } - - try { - new UidRange(-200, -100); - fail("Exception not thrown for negative stop UID"); - } catch (IllegalArgumentException expected) { - } - } - - @Test - public void testStopLessThanStartDisallowed() { - final int x = 4195000; - try { - new UidRange(x, x - 1); - fail("Exception not thrown for negative-length UID range"); - } catch (IllegalArgumentException expected) { - } - } -}
\ No newline at end of file diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 1cfc3f9f9e5c..60670ade1a96 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -199,7 +199,7 @@ import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.NetworkStack; import android.net.NetworkStackClient; -import android.net.NetworkState; +import android.net.NetworkStateSnapshot; import android.net.NetworkTestResultParcelable; import android.net.OemNetworkPreferences; import android.net.ProxyInfo; @@ -1462,7 +1462,6 @@ public class ConnectivityServiceTest { mDeps = makeDependencies(); returnRealCallingUid(); mService = new ConnectivityService(mServiceContext, - mNetworkManagementService, mStatsService, mMockDnsResolver, mock(IpConnectivityLog.class), @@ -5485,7 +5484,7 @@ public class ConnectivityServiceTest { UnderlyingNetworkInfo[].class); verify(mStatsService, atLeastOnce()).forceUpdateIfaces(networksCaptor.capture(), - any(NetworkState[].class), eq(defaultIface), vpnInfosCaptor.capture()); + any(NetworkStateSnapshot[].class), eq(defaultIface), vpnInfosCaptor.capture()); assertSameElementsNoDuplicates(networksCaptor.getValue(), networks); @@ -5555,9 +5554,8 @@ public class ConnectivityServiceTest { // Temp metered change shouldn't update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED); waitForIdle(); - verify(mStatsService, never()) - .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME), - eq(new UnderlyingNetworkInfo[0])); + verify(mStatsService, never()).forceUpdateIfaces(eq(onlyCell), any( + NetworkStateSnapshot[].class), eq(MOBILE_IFNAME), eq(new UnderlyingNetworkInfo[0])); reset(mStatsService); // Roaming change should update ifaces @@ -5639,7 +5637,7 @@ public class ConnectivityServiceTest { // Confirm that we never tell NetworkStatsService that cell is no longer the underlying // network for the VPN... verify(mStatsService, never()).forceUpdateIfaces(any(Network[].class), - any(NetworkState[].class), any() /* anyString() doesn't match null */, + any(NetworkStateSnapshot[].class), any() /* anyString() doesn't match null */, argThat(infos -> infos[0].underlyingIfaces.size() == 1 && WIFI_IFNAME.equals(infos[0].underlyingIfaces.get(0)))); verifyNoMoreInteractions(mStatsService); @@ -5653,7 +5651,7 @@ public class ConnectivityServiceTest { mEthernetNetworkAgent.connect(false); waitForIdle(); verify(mStatsService).forceUpdateIfaces(any(Network[].class), - any(NetworkState[].class), any() /* anyString() doesn't match null */, + any(NetworkStateSnapshot[].class), any() /* anyString() doesn't match null */, argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.size() == 1 && WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces.get(0)))); mEthernetNetworkAgent.disconnect(); @@ -7856,7 +7854,6 @@ public class ConnectivityServiceTest { cellLp.addRoute(defaultRoute); cellLp.addRoute(ipv6Subnet); mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); - reset(mNetworkManagementService); reset(mMockDnsResolver); reset(mMockNetd); reset(mBatteryStatsService); @@ -7896,7 +7893,6 @@ public class ConnectivityServiceTest { verifyNoMoreInteractions(mMockNetd); verifyNoMoreInteractions(mMockDnsResolver); - reset(mNetworkManagementService); reset(mMockNetd); reset(mMockDnsResolver); when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME)) @@ -7996,7 +7992,6 @@ public class ConnectivityServiceTest { verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME); verifyNoMoreInteractions(mMockNetd); verifyNoMoreInteractions(mMockDnsResolver); - reset(mNetworkManagementService); reset(mMockNetd); reset(mMockDnsResolver); when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME)) @@ -8233,7 +8228,6 @@ public class ConnectivityServiceTest { final LinkProperties cellLp = new LinkProperties(); cellLp.setInterfaceName(MOBILE_IFNAME); mCellNetworkAgent.sendLinkProperties(cellLp); - reset(mNetworkManagementService); mCellNetworkAgent.connect(true); networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); verify(mMockNetd, times(1)).idletimerAddInterface(eq(MOBILE_IFNAME), anyInt(), @@ -8927,8 +8921,8 @@ public class ConnectivityServiceTest { ConnectivityManager.getNetworkTypeName(TYPE_MOBILE), TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE)); return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(), - nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, null, - 0, INVALID_UID, mQosCallbackTracker); + nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, 0, + INVALID_UID, mQosCallbackTracker); } @Test diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java index 52cb836e19c8..a913673c2a1e 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java @@ -41,7 +41,6 @@ import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkProvider; import android.os.Binder; -import android.os.INetworkManagementService; import android.text.format.DateUtils; import androidx.test.filters.SmallTest; @@ -74,7 +73,6 @@ public class LingerMonitorTest { @Mock ConnectivityService mConnService; @Mock IDnsResolver mDnsResolver; @Mock INetd mNetd; - @Mock INetworkManagementService mNMS; @Mock Context mCtx; @Mock NetworkNotificationManager mNotifier; @Mock Resources mResources; @@ -358,8 +356,8 @@ public class LingerMonitorTest { caps.addTransportType(transport); NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info, new LinkProperties(), caps, 50, mCtx, null, new NetworkAgentConfig() /* config */, - mConnService, mNetd, mDnsResolver, mNMS, NetworkProvider.ID_NONE, - Binder.getCallingUid(), mQosCallbackTracker); + mConnService, mNetd, mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(), + mQosCallbackTracker); nai.everValidated = true; return nai; } diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java index 4f65b67fa3da..5f56e25356c2 100644 --- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java +++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java @@ -36,7 +36,6 @@ import android.net.LinkProperties; import android.net.NetworkAgentConfig; import android.net.NetworkInfo; import android.os.Handler; -import android.os.INetworkManagementService; import android.os.test.TestLooper; import androidx.test.filters.SmallTest; @@ -67,7 +66,6 @@ public class Nat464XlatTest { @Mock ConnectivityService mConnectivity; @Mock IDnsResolver mDnsResolver; @Mock INetd mNetd; - @Mock INetworkManagementService mNms; @Mock NetworkAgentInfo mNai; TestLooper mLooper; @@ -75,7 +73,7 @@ public class Nat464XlatTest { NetworkAgentConfig mAgentConfig = new NetworkAgentConfig(); Nat464Xlat makeNat464Xlat() { - return new Nat464Xlat(mNai, mNetd, mDnsResolver, mNms) { + return new Nat464Xlat(mNai, mNetd, mDnsResolver) { @Override protected int getNetId() { return NETID; } @@ -206,7 +204,6 @@ public class Nat464XlatTest { // Start clat. nat.start(); - verify(mNms).registerObserver(eq(nat)); verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX)); // Stacked interface up notification arrives. @@ -225,7 +222,6 @@ public class Nat464XlatTest { verify(mNetd).clatdStop(eq(BASE_IFACE)); verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture()); - verify(mNms).unregisterObserver(eq(nat)); assertTrue(c.getValue().getStackedLinks().isEmpty()); assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE)); verify(mDnsResolver).stopPrefix64Discovery(eq(NETID)); @@ -235,7 +231,7 @@ public class Nat464XlatTest { nat.interfaceRemoved(STACKED_IFACE); mLooper.dispatchNext(); - verifyNoMoreInteractions(mNetd, mNms, mConnectivity); + verifyNoMoreInteractions(mNetd, mConnectivity); } @Test @@ -346,7 +342,6 @@ public class Nat464XlatTest { nat.start(); - verify(mNms).registerObserver(eq(nat)); verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX)); // Stacked interface up notification arrives. @@ -365,7 +360,6 @@ public class Nat464XlatTest { verify(mNetd).clatdStop(eq(BASE_IFACE)); verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture()); - verify(mNms).unregisterObserver(eq(nat)); verify(mDnsResolver).stopPrefix64Discovery(eq(NETID)); assertTrue(c.getValue().getStackedLinks().isEmpty()); assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE)); @@ -374,7 +368,7 @@ public class Nat464XlatTest { // ConnectivityService stops clat: no-op. nat.stop(); - verifyNoMoreInteractions(mNetd, mNms, mConnectivity); + verifyNoMoreInteractions(mNetd, mConnectivity); } private void checkStopBeforeClatdStarts(boolean dueToDisconnect) throws Exception { @@ -386,7 +380,6 @@ public class Nat464XlatTest { nat.start(); - verify(mNms).registerObserver(eq(nat)); verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX)); // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...) @@ -394,7 +387,6 @@ public class Nat464XlatTest { nat.stop(); verify(mNetd).clatdStop(eq(BASE_IFACE)); - verify(mNms).unregisterObserver(eq(nat)); verify(mDnsResolver).stopPrefix64Discovery(eq(NETID)); assertIdle(nat); @@ -408,7 +400,7 @@ public class Nat464XlatTest { assertIdle(nat); - verifyNoMoreInteractions(mNetd, mNms, mConnectivity); + verifyNoMoreInteractions(mNetd, mConnectivity); } @Test @@ -430,7 +422,6 @@ public class Nat464XlatTest { nat.start(); - verify(mNms).registerObserver(eq(nat)); verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX)); // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...) @@ -438,11 +429,10 @@ public class Nat464XlatTest { nat.stop(); verify(mNetd).clatdStop(eq(BASE_IFACE)); - verify(mNms).unregisterObserver(eq(nat)); verify(mDnsResolver).stopPrefix64Discovery(eq(NETID)); assertIdle(nat); - verifyNoMoreInteractions(mNetd, mNms, mConnectivity); + verifyNoMoreInteractions(mNetd, mConnectivity); } @Test diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index 54d6fb9f2c12..9334e2c4ad77 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -19,9 +19,7 @@ package com.android.server.net; import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.TYPE_MOBILE; -import static android.net.ConnectivityManager.TYPE_VPN; import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.net.NetworkIdentity.OEM_NONE; import static android.net.NetworkIdentity.OEM_PAID; import static android.net.NetworkIdentity.OEM_PRIVATE; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; @@ -86,7 +84,7 @@ import android.net.INetworkStatsSession; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.NetworkState; +import android.net.NetworkStateSnapshot; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; @@ -286,7 +284,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectDefaultSettings(); - NetworkState[] states = new NetworkState[] {buildWifiState()}; + NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -329,7 +327,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectDefaultSettings(); - NetworkState[] states = new NetworkState[] {buildWifiState()}; + NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -403,7 +401,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS); - NetworkState[] states = new NetworkState[] {buildWifiState()}; + NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -444,7 +442,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { public void testUidStatsAcrossNetworks() throws Exception { // pretend first mobile network comes online expectDefaultSettings(); - NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)}; + NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildMobile3gState(IMSI_1)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -475,7 +473,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // disappearing, to verify we don't count backwards. incrementCurrentTime(HOUR_IN_MILLIS); expectDefaultSettings(); - states = new NetworkState[] {buildMobile3gState(IMSI_2)}; + states = new NetworkStateSnapshot[] {buildMobile3gState(IMSI_2)}; expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .insertEntry(TEST_IFACE, 2048L, 16L, 512L, 4L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) @@ -519,7 +517,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { public void testUidRemovedIsMoved() throws Exception { // pretend that network comes online expectDefaultSettings(); - NetworkState[] states = new NetworkState[] {buildWifiState()}; + NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -583,7 +581,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_LTE); final NetworkTemplate template5g = buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_NR); - final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)}; + final NetworkStateSnapshot[] states = + new NetworkStateSnapshot[]{buildMobile3gState(IMSI_1)}; // 3G network comes online. expectNetworkStatsSummary(buildEmptyStats()); @@ -673,7 +672,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_NO); // OEM_PAID network comes online. - NetworkState[] states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false, + NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{ + buildOemManagedMobileState(IMSI_1, false, new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PAID})}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -688,7 +688,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { forcePollAndWaitForIdle(); // OEM_PRIVATE network comes online. - states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false, + states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false, new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE})}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -703,7 +703,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { forcePollAndWaitForIdle(); // OEM_PAID + OEM_PRIVATE network comes online. - states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false, + states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false, new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, NetworkCapabilities.NET_CAPABILITY_OEM_PAID})}; expectNetworkStatsSummary(buildEmptyStats()); @@ -719,7 +719,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { forcePollAndWaitForIdle(); // OEM_NONE network comes online. - states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false, new int[]{})}; + states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false, new int[]{})}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), @@ -771,7 +771,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { public void testSummaryForAllUid() throws Exception { // pretend that network comes online expectDefaultSettings(); - NetworkState[] states = new NetworkState[] {buildWifiState()}; + NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -830,7 +830,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { public void testDetailedUidStats() throws Exception { // pretend that network comes online expectDefaultSettings(); - NetworkState[] states = new NetworkState[] {buildWifiState()}; + NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -871,9 +871,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { final String stackedIface = "stacked-test0"; final LinkProperties stackedProp = new LinkProperties(); stackedProp.setInterfaceName(stackedIface); - final NetworkState wifiState = buildWifiState(); + final NetworkStateSnapshot wifiState = buildWifiState(); wifiState.linkProperties.addStackedLink(stackedProp); - NetworkState[] states = new NetworkState[] {wifiState}; + NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {wifiState}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -929,7 +929,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { public void testForegroundBackground() throws Exception { // pretend that network comes online expectDefaultSettings(); - NetworkState[] states = new NetworkState[] {buildWifiState()}; + NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -986,8 +986,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { public void testMetered() throws Exception { // pretend that network comes online expectDefaultSettings(); - NetworkState[] states = - new NetworkState[] {buildWifiState(true /* isMetered */, TEST_IFACE)}; + NetworkStateSnapshot[] states = + new NetworkStateSnapshot[] {buildWifiState(true /* isMetered */, TEST_IFACE)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -1026,8 +1026,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { public void testRoaming() throws Exception { // pretend that network comes online expectDefaultSettings(); - NetworkState[] states = - new NetworkState[] {buildMobile3gState(IMSI_1, true /* isRoaming */)}; + NetworkStateSnapshot[] states = + new NetworkStateSnapshot[] {buildMobile3gState(IMSI_1, true /* isRoaming */)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -1065,7 +1065,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { public void testTethering() throws Exception { // pretend first mobile network comes online expectDefaultSettings(); - final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)}; + final NetworkStateSnapshot[] states = + new NetworkStateSnapshot[]{buildMobile3gState(IMSI_1)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -1122,7 +1123,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectDefaultSettings(); - NetworkState[] states = new NetworkState[] {buildWifiState()}; + NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -1220,8 +1221,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { public void testStatsProviderUpdateStats() throws Exception { // Pretend that network comes online. expectDefaultSettings(); - final NetworkState[] states = - new NetworkState[]{buildWifiState(true /* isMetered */, TEST_IFACE)}; + final NetworkStateSnapshot[] states = + new NetworkStateSnapshot[]{buildWifiState(true /* isMetered */, TEST_IFACE)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -1282,8 +1283,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { public void testStatsProviderSetAlert() throws Exception { // Pretend that network comes online. expectDefaultSettings(); - NetworkState[] states = - new NetworkState[]{buildWifiState(true /* isMetered */, TEST_IFACE)}; + NetworkStateSnapshot[] states = + new NetworkStateSnapshot[]{buildWifiState(true /* isMetered */, TEST_IFACE)}; mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new UnderlyingNetworkInfo[0]); @@ -1326,7 +1327,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UNKNOWN); final NetworkTemplate templateAll = buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL); - final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)}; + final NetworkStateSnapshot[] states = + new NetworkStateSnapshot[]{buildMobile3gState(IMSI_1)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -1401,7 +1403,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { public void testOperationCount_nonDefault_traffic() throws Exception { // Pretend mobile network comes online, but wifi is the default network. expectDefaultSettings(); - NetworkState[] states = new NetworkState[]{ + NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{ buildWifiState(true /*isMetered*/, TEST_IFACE2), buildMobile3gState(IMSI_1)}; expectNetworkStatsUidDetail(buildEmptyStats()); mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), @@ -1489,7 +1491,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(buildEmptyStats()); } - private String getActiveIface(NetworkState... states) throws Exception { + private String getActiveIface(NetworkStateSnapshot... states) throws Exception { if (states == null || states.length == 0 || states[0].linkProperties == null) { return null; } @@ -1565,11 +1567,11 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { assertEquals("unexpected operations", operations, entry.operations); } - private static NetworkState buildWifiState() { + private static NetworkStateSnapshot buildWifiState() { return buildWifiState(false, TEST_IFACE); } - private static NetworkState buildWifiState(boolean isMetered, @NonNull String iface) { + private static NetworkStateSnapshot buildWifiState(boolean isMetered, @NonNull String iface) { final LinkProperties prop = new LinkProperties(); prop.setInterfaceName(iface); final NetworkCapabilities capabilities = new NetworkCapabilities(); @@ -1577,35 +1579,30 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true); capabilities.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); capabilities.setSSID(TEST_SSID); - return new NetworkState(TYPE_WIFI, prop, capabilities, WIFI_NETWORK, null); + return new NetworkStateSnapshot(WIFI_NETWORK, capabilities, prop, null, TYPE_WIFI); } - private static NetworkState buildMobile3gState(String subscriberId) { + private static NetworkStateSnapshot buildMobile3gState(String subscriberId) { return buildMobile3gState(subscriberId, false /* isRoaming */); } - private static NetworkState buildMobile3gState(String subscriberId, boolean isRoaming) { + private static NetworkStateSnapshot buildMobile3gState(String subscriberId, boolean isRoaming) { final LinkProperties prop = new LinkProperties(); prop.setInterfaceName(TEST_IFACE); final NetworkCapabilities capabilities = new NetworkCapabilities(); capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false); capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming); capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); - return new NetworkState(TYPE_MOBILE, prop, capabilities, MOBILE_NETWORK, subscriberId); + return new NetworkStateSnapshot( + MOBILE_NETWORK, capabilities, prop, subscriberId, TYPE_MOBILE); } private NetworkStats buildEmptyStats() { return new NetworkStats(getElapsedRealtime(), 0); } - private static NetworkState buildVpnState() { - final LinkProperties prop = new LinkProperties(); - prop.setInterfaceName(TUN_IFACE); - return new NetworkState(TYPE_VPN, prop, new NetworkCapabilities(), VPN_NETWORK, null); - } - - private static NetworkState buildOemManagedMobileState(String subscriberId, boolean isRoaming, - int[] oemNetCapabilities) { + private static NetworkStateSnapshot buildOemManagedMobileState( + String subscriberId, boolean isRoaming, int[] oemNetCapabilities) { final LinkProperties prop = new LinkProperties(); prop.setInterfaceName(TEST_IFACE); final NetworkCapabilities capabilities = new NetworkCapabilities(); @@ -1615,7 +1612,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { capabilities.setCapability(nc, true); } capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); - return new NetworkState(TYPE_MOBILE, prop, capabilities, MOBILE_NETWORK, subscriberId); + return new NetworkStateSnapshot(MOBILE_NETWORK, capabilities, prop, subscriberId, + TYPE_MOBILE); } private long getElapsedRealtime() { diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index b760958e0edc..13e090d9d843 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -2263,6 +2263,16 @@ int LinkCommand::Action(const std::vector<std::string>& args) { return 1; } + if (shared_lib_ && options_.private_symbols) { + // If a shared library styleable in a public R.java uses a private attribute, attempting to + // reference the private attribute within the styleable array will cause a link error because + // the private attribute will not be emitted in the public R.java. + context.GetDiagnostics()->Error(DiagMessage() + << "--shared-lib cannot currently be used in combination with" + << " --private-symbols"); + return 1; + } + if (options_.merge_only && !static_lib_) { context.GetDiagnostics()->Error( DiagMessage() << "the --merge-only flag can be only used when building a static library"); diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp index 062dd8eac975..73072a963d09 100644 --- a/tools/aapt2/cmd/Link_test.cpp +++ b/tools/aapt2/cmd/Link_test.cpp @@ -14,13 +14,16 @@ * limitations under the License. */ -#include "AppInfo.h" #include "Link.h" +#include <android-base/file.h> + +#include "AppInfo.h" #include "LoadedApk.h" #include "test/Test.h" using testing::Eq; +using testing::HasSubstr; using testing::Ne; namespace aapt { @@ -317,4 +320,76 @@ TEST_F(LinkTest, AppInfoWithUsesSplit) { ASSERT_TRUE(Link(link_args, feature2_files_dir, &diag)); } +TEST_F(LinkTest, SharedLibraryAttributeRJava) { + StdErrDiagnostics diag; + const std::string lib_values = + R"(<resources> + <attr name="foo"/> + <public type="attr" name="foo" id="0x00010001"/> + <declare-styleable name="LibraryStyleable"> + <attr name="foo" /> + </declare-styleable> + </resources>)"; + + const std::string client_values = + R"(<resources> + <attr name="bar" /> + <declare-styleable name="ClientStyleable"> + <attr name="com.example.lib:foo" /> + <attr name="bar" /> + </declare-styleable> + </resources>)"; + + // Build a library with a public attribute + const std::string lib_res = GetTestPath("library-res"); + ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"), lib_values, lib_res, &diag)); + + const std::string lib_apk = GetTestPath("library.apk"); + const std::string lib_java = GetTestPath("library_java"); + // clang-format off + auto lib_manifest = ManifestBuilder(this) + .SetPackageName("com.example.lib") + .Build(); + + auto lib_link_args = LinkCommandBuilder(this) + .SetManifestFile(lib_manifest) + .AddFlag("--shared-lib") + .AddParameter("--java", lib_java) + .AddCompiledResDir(lib_res, &diag) + .Build(lib_apk); + // clang-format on + ASSERT_TRUE(Link(lib_link_args, &diag)); + + const std::string lib_r_java = lib_java + "/com/example/lib/R.java"; + std::string lib_r_contents; + ASSERT_TRUE(android::base::ReadFileToString(lib_r_java, &lib_r_contents)); + EXPECT_THAT(lib_r_contents, HasSubstr(" public static int foo=0x00010001;")); + EXPECT_THAT(lib_r_contents, HasSubstr(" com.example.lib.R.attr.foo")); + + // Build a client that uses the library attribute in a declare-styleable + const std::string client_res = GetTestPath("client-res"); + ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"), client_values, client_res, &diag)); + + const std::string client_apk = GetTestPath("client.apk"); + const std::string client_java = GetTestPath("client_java"); + // clang-format off + auto client_manifest = ManifestBuilder(this) + .SetPackageName("com.example.client") + .Build(); + + auto client_link_args = LinkCommandBuilder(this) + .SetManifestFile(client_manifest) + .AddParameter("--java", client_java) + .AddParameter("-I", lib_apk) + .AddCompiledResDir(client_res, &diag) + .Build(client_apk); + // clang-format on + ASSERT_TRUE(Link(client_link_args, &diag)); + + const std::string client_r_java = client_java + "/com/example/client/R.java"; + std::string client_r_contents; + ASSERT_TRUE(android::base::ReadFileToString(client_r_java, &client_r_contents)); + EXPECT_THAT(client_r_contents, HasSubstr(" com.example.lib.R.attr.foo, 0x7f010000")); +} + } // namespace aapt diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp index eb0ade62d542..4b90b4f534cc 100644 --- a/tools/aapt2/format/binary/TableFlattener.cpp +++ b/tools/aapt2/format/binary/TableFlattener.cpp @@ -570,7 +570,6 @@ class PackageFlattener { ResourceEntry* entry = sorted_entries->at(entryIndex); // Populate the config masks for this entry. - if (entry->visibility.level == Visibility::Level::kPublic) { config_masks[entry->id.value()] |= util::HostToDevice32(ResTable_typeSpec::SPEC_PUBLIC); } diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h index 1e4b6816075a..995495ac56a8 100644 --- a/tools/aapt2/java/ClassDefinition.h +++ b/tools/aapt2/java/ClassDefinition.h @@ -70,8 +70,8 @@ class PrimitiveMember : public ClassMember { return name_; } - void Print(bool final, text::Printer* printer, bool strip_api_annotations = false) - const override { + void Print(bool final, text::Printer* printer, + bool strip_api_annotations = false) const override { using std::to_string; ClassMember::Print(final, printer, strip_api_annotations); @@ -127,13 +127,13 @@ using IntMember = PrimitiveMember<uint32_t>; using ResourceMember = PrimitiveMember<ResourceId>; using StringMember = PrimitiveMember<std::string>; -template <typename T> +template <typename T, typename StringConverter> class PrimitiveArrayMember : public ClassMember { public: explicit PrimitiveArrayMember(const android::StringPiece& name) : name_(name.to_string()) {} void AddElement(const T& val) { - elements_.push_back(val); + elements_.emplace_back(val); } bool empty() const override { @@ -158,7 +158,7 @@ class PrimitiveArrayMember : public ClassMember { printer->Println(); } - printer->Print(to_string(*current)); + printer->Print(StringConverter::ToString(*current)); if (std::distance(current, end) > 1) { printer->Print(", "); } @@ -175,7 +175,24 @@ class PrimitiveArrayMember : public ClassMember { std::vector<T> elements_; }; -using ResourceArrayMember = PrimitiveArrayMember<ResourceId>; +struct FieldReference { + explicit FieldReference(std::string reference) : ref(std::move(reference)) { + } + std::string ref; +}; + +struct ResourceArrayMemberStringConverter { + static std::string ToString(const std::variant<ResourceId, FieldReference>& ref) { + if (auto id = std::get_if<ResourceId>(&ref)) { + return to_string(*id); + } else { + return std::get<FieldReference>(ref).ref; + } + } +}; + +using ResourceArrayMember = PrimitiveArrayMember<std::variant<ResourceId, FieldReference>, + ResourceArrayMemberStringConverter>; // Represents a method in a class. class MethodDefinition : public ClassMember { diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp index f0f839d968d5..59dd481607e9 100644 --- a/tools/aapt2/java/JavaClassGenerator.cpp +++ b/tools/aapt2/java/JavaClassGenerator.cpp @@ -224,7 +224,16 @@ static bool operator<(const StyleableAttr& lhs, const StyleableAttr& rhs) { return cmp_ids_dynamic_after_framework(lhs_id, rhs_id); } -void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const ResourceId& id, +static FieldReference GetRFieldReference(const ResourceName& name, + StringPiece fallback_package_name) { + const std::string package_name = + name.package.empty() ? fallback_package_name.to_string() : name.package; + const std::string entry = JavaClassGenerator::TransformToFieldName(name.entry); + return FieldReference( + StringPrintf("%s.R.%s.%s", package_name.c_str(), to_string(name.type).data(), entry.c_str())); +} + +bool JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const ResourceId& id, const Styleable& styleable, const StringPiece& package_name_to_generate, ClassDefinition* out_class_def, @@ -340,14 +349,29 @@ void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res // Add the ResourceIds to the array member. for (size_t i = 0; i < attr_count; i++) { - const ResourceId id = sorted_attributes[i].attr_ref->id.value_or_default(ResourceId(0)); - array_def->AddElement(id); + const StyleableAttr& attr = sorted_attributes[i]; + std::string r_txt_contents; + if (attr.symbol && attr.symbol.value().is_dynamic) { + if (!attr.attr_ref->name) { + error_ = "unable to determine R.java field name of dynamic resource"; + return false; + } + + const FieldReference field_name = + GetRFieldReference(attr.attr_ref->name.value(), package_name_to_generate); + array_def->AddElement(field_name); + r_txt_contents = field_name.ref; + } else { + const ResourceId attr_id = attr.attr_ref->id.value_or_default(ResourceId(0)); + array_def->AddElement(attr_id); + r_txt_contents = to_string(attr_id); + } if (r_txt_printer != nullptr) { if (i != 0) { r_txt_printer->Print(","); } - r_txt_printer->Print(" ").Print(id.to_string()); + r_txt_printer->Print(" ").Print(r_txt_contents); } } @@ -419,19 +443,7 @@ void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res } } - // If there is a rewrite method to generate, add the statements that rewrite package IDs - // for this styleable. - if (out_rewrite_method != nullptr) { - out_rewrite_method->AppendStatement( - StringPrintf("for (int i = 0; i < styleable.%s.length; i++) {", array_field_name.data())); - out_rewrite_method->AppendStatement( - StringPrintf(" if ((styleable.%s[i] & 0xff000000) == 0) {", array_field_name.data())); - out_rewrite_method->AppendStatement( - StringPrintf(" styleable.%s[i] = (styleable.%s[i] & 0x00ffffff) | packageIdBits;", - array_field_name.data(), array_field_name.data())); - out_rewrite_method->AppendStatement(" }"); - out_rewrite_method->AppendStatement("}"); - } + return true; } void JavaClassGenerator::ProcessResource(const ResourceNameRef& name, const ResourceId& id, @@ -448,8 +460,7 @@ void JavaClassGenerator::ProcessResource(const ResourceNameRef& name, const Reso const std::string field_name = TransformToFieldName(name.entry); if (out_class_def != nullptr) { - std::unique_ptr<ResourceMember> resource_member = - util::make_unique<ResourceMember>(field_name, real_id); + auto resource_member = util::make_unique<ResourceMember>(field_name, real_id); // Build the comments and annotations for this entry. AnnotationProcessor* processor = resource_member->GetCommentBuilder(); @@ -551,12 +562,11 @@ bool JavaClassGenerator::ProcessType(const StringPiece& package_name_to_generate if (resource_name.type == ResourceType::kStyleable) { CHECK(!entry->values.empty()); - - const Styleable* styleable = - static_cast<const Styleable*>(entry->values.front()->value.get()); - - ProcessStyleable(resource_name, id, *styleable, package_name_to_generate, out_type_class_def, - out_rewrite_method_def, r_txt_printer); + const auto styleable = reinterpret_cast<const Styleable*>(entry->values.front()->value.get()); + if (!ProcessStyleable(resource_name, id, *styleable, package_name_to_generate, + out_type_class_def, out_rewrite_method_def, r_txt_printer)) { + return false; + } } else { ProcessResource(resource_name, id, *entry, out_type_class_def, out_rewrite_method_def, r_txt_printer); @@ -626,8 +636,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, if (type->type == ResourceType::kAttr) { // Also include private attributes in this same class. - const ResourceTableType* priv_type = package->FindType(ResourceType::kAttrPrivate); - if (priv_type) { + if (const ResourceTableType* priv_type = package->FindType(ResourceType::kAttrPrivate)) { if (!ProcessType(package_name_to_generate, *package, *priv_type, class_def.get(), rewrite_method.get(), r_txt_printer.get())) { return false; diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h index 853120b3cb98..d9d1b39805f9 100644 --- a/tools/aapt2/java/JavaClassGenerator.h +++ b/tools/aapt2/java/JavaClassGenerator.h @@ -105,7 +105,7 @@ class JavaClassGenerator { // Writes a styleable resource to the R.java file, optionally writing out a rewrite rule for // its package ID if `out_rewrite_method` is not nullptr. // `package_name_to_generate` is the package - void ProcessStyleable(const ResourceNameRef& name, const ResourceId& id, + bool ProcessStyleable(const ResourceNameRef& name, const ResourceId& id, const Styleable& styleable, const android::StringPiece& package_name_to_generate, ClassDefinition* out_class_def, MethodDefinition* out_rewrite_method, diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp index 04e20101a0dd..ec5b4151b1a6 100644 --- a/tools/aapt2/java/JavaClassGenerator_test.cpp +++ b/tools/aapt2/java/JavaClassGenerator_test.cpp @@ -581,7 +581,7 @@ TEST(JavaClassGeneratorTest, SortsDynamicAttributesAfterFrameworkAttributes) { out.Flush(); EXPECT_THAT(output, HasSubstr("public static final int[] MyStyleable={")); - EXPECT_THAT(output, HasSubstr("0x01010000, 0x00010000")); + EXPECT_THAT(output, HasSubstr("0x01010000, lib.R.attr.dynamic_attr")); EXPECT_THAT(output, HasSubstr("public static final int MyStyleable_android_framework_attr=0;")); EXPECT_THAT(output, HasSubstr("public static final int MyStyleable_dynamic_attr=1;")); } diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp index daedc2a14767..98ee63d2e5c6 100644 --- a/tools/aapt2/process/SymbolTable.cpp +++ b/tools/aapt2/process/SymbolTable.cpp @@ -370,11 +370,11 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindByName( } else { s = util::make_unique<SymbolTable::Symbol>(); s->id = res_id; - s->is_dynamic = IsPackageDynamic(ResourceId(res_id).package_id(), real_name.package); } if (s) { s->is_public = (type_spec_flags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0; + s->is_dynamic = IsPackageDynamic(ResourceId(res_id).package_id(), real_name.package); return s; } return {}; @@ -417,11 +417,11 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindById( } else { s = util::make_unique<SymbolTable::Symbol>(); s->id = id; - s->is_dynamic = IsPackageDynamic(ResourceId(id).package_id(), name.package); } if (s) { s->is_public = (*flags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0; + s->is_dynamic = IsPackageDynamic(ResourceId(id).package_id(), name.package); return s; } return {}; diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp index 5386802dbc8e..f94f0fe1144a 100644 --- a/tools/aapt2/test/Fixture.cpp +++ b/tools/aapt2/test/Fixture.cpp @@ -18,18 +18,17 @@ #include <dirent.h> -#include "android-base/errors.h" -#include "android-base/file.h" -#include "android-base/stringprintf.h" -#include "android-base/utf8.h" -#include "androidfw/StringPiece.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" +#include <android-base/errors.h> +#include <android-base/file.h> +#include <android-base/stringprintf.h> +#include <android-base/utf8.h> +#include <androidfw/StringPiece.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> #include "cmd/Compile.h" #include "cmd/Link.h" #include "io/FileStream.h" -#include "io/Util.h" #include "util/Files.h" using testing::Eq; @@ -170,4 +169,74 @@ void CommandTestFixture::AssertLoadXml(LoadedApk* apk, const io::IData* data, } } +ManifestBuilder::ManifestBuilder(CommandTestFixture* fixture) : fixture_(fixture) { +} + +ManifestBuilder& ManifestBuilder::SetPackageName(const std::string& package_name) { + package_name_ = package_name; + return *this; +} + +ManifestBuilder& ManifestBuilder::AddContents(const std::string& contents) { + contents_ += contents + "\n"; + return *this; +} + +std::string ManifestBuilder::Build(const std::string& file_path) { + const char* manifest_template = R"( + <manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="%s"> + %s + </manifest>)"; + + fixture_->WriteFile(file_path, android::base::StringPrintf( + manifest_template, package_name_.c_str(), contents_.c_str())); + return file_path; +} + +std::string ManifestBuilder::Build() { + return Build(fixture_->GetTestPath("AndroidManifest.xml")); +} + +LinkCommandBuilder::LinkCommandBuilder(CommandTestFixture* fixture) : fixture_(fixture) { +} + +LinkCommandBuilder& LinkCommandBuilder::SetManifestFile(const std::string& file) { + manifest_supplied_ = true; + args_.emplace_back("--manifest"); + args_.emplace_back(file); + return *this; +} + +LinkCommandBuilder& LinkCommandBuilder::AddFlag(const std::string& flag) { + args_.emplace_back(flag); + return *this; +} + +LinkCommandBuilder& LinkCommandBuilder::AddCompiledResDir(const std::string& dir, + IDiagnostics* diag) { + if (auto files = file::FindFiles(dir, diag)) { + for (std::string& compile_file : files.value()) { + args_.emplace_back(file::BuildPath({dir, compile_file})); + } + } + return *this; +} + +LinkCommandBuilder& LinkCommandBuilder::AddParameter(const std::string& param, + const std::string& value) { + args_.emplace_back(param); + args_.emplace_back(value); + return *this; +} + +std::vector<std::string> LinkCommandBuilder::Build(const std::string& out_apk) { + if (!manifest_supplied_) { + SetManifestFile(ManifestBuilder(fixture_).Build()); + } + args_.emplace_back("-o"); + args_.emplace_back(out_apk); + return args_; +} + } // namespace aapt
\ No newline at end of file diff --git a/tools/aapt2/test/Fixture.h b/tools/aapt2/test/Fixture.h index 457d65e30b65..f8c4889aee3b 100644 --- a/tools/aapt2/test/Fixture.h +++ b/tools/aapt2/test/Fixture.h @@ -32,7 +32,7 @@ namespace aapt { class TestDirectoryFixture : public ::testing::Test { public: TestDirectoryFixture() = default; - virtual ~TestDirectoryFixture() = default; + ~TestDirectoryFixture() override = default; // Creates the test directory or clears its contents if it contains previously created files. void SetUp() override; @@ -41,14 +41,14 @@ class TestDirectoryFixture : public ::testing::Test { void TearDown() override; // Retrieve the test directory of the fixture. - const android::StringPiece GetTestDirectory() { + android::StringPiece GetTestDirectory() { return temp_dir_; } // Retrieves the absolute path of the specified relative path in the test directory. Directories // should be separated using forward slashes ('/'), and these slashes will be translated to // backslashes when running Windows tests. - const std::string GetTestPath(const android::StringPiece& path) { + std::string GetTestPath(const android::StringPiece& path) { std::string base = temp_dir_; for (android::StringPiece part : util::Split(path, '/')) { file::AppendPath(&base, part); @@ -68,7 +68,7 @@ class TestDirectoryFixture : public ::testing::Test { class CommandTestFixture : public TestDirectoryFixture { public: CommandTestFixture() = default; - virtual ~CommandTestFixture() = default; + ~CommandTestFixture() override = default; // Wries the contents of the file to the specified path. The file is compiled and the flattened // file is written to the out directory. @@ -99,6 +99,33 @@ class CommandTestFixture : public TestDirectoryFixture { DISALLOW_COPY_AND_ASSIGN(CommandTestFixture); }; +struct ManifestBuilder { + explicit ManifestBuilder(CommandTestFixture* fixture); + ManifestBuilder& AddContents(const std::string& contents); + ManifestBuilder& SetPackageName(const std::string& package_name); + std::string Build(const std::string& file_path); + std::string Build(); + + private: + CommandTestFixture* fixture_; + std::string package_name_ = CommandTestFixture::kDefaultPackageName; + std::string contents_; +}; + +struct LinkCommandBuilder { + explicit LinkCommandBuilder(CommandTestFixture* fixture); + LinkCommandBuilder& AddCompiledResDir(const std::string& dir, IDiagnostics* diag); + LinkCommandBuilder& AddFlag(const std::string& flag); + LinkCommandBuilder& AddParameter(const std::string& param, const std::string& value); + LinkCommandBuilder& SetManifestFile(const std::string& manifest_path); + std::vector<std::string> Build(const std::string& out_apk_path); + + private: + CommandTestFixture* fixture_; + std::vector<std::string> args_; + bool manifest_supplied_ = false; +}; + } // namespace aapt #endif // AAPT_TEST_FIXTURE_H
\ No newline at end of file |