diff options
194 files changed, 4458 insertions, 1953 deletions
diff --git a/Android.bp b/Android.bp index a61b5472e6fc..4e2b156afbbf 100644 --- a/Android.bp +++ b/Android.bp @@ -487,7 +487,7 @@ java_library { "framework-minus-apex", "updatable_media_stubs", "framework_mediaprovider_stubs", - "framework-appsearch-stubs", + "framework-appsearch", // TODO(b/146218515): should be framework-appsearch-stubs "framework-sdkextensions-stubs-systemapi", // TODO(b/146167933): Use framework-statsd-stubs instead. "framework-statsd", diff --git a/apex/appsearch/framework/Android.bp b/apex/appsearch/framework/Android.bp index 60cc3bec0a9d..1f30dda21ef7 100644 --- a/apex/appsearch/framework/Android.bp +++ b/apex/appsearch/framework/Android.bp @@ -30,10 +30,29 @@ java_library { libs: [ "framework-minus-apex", // TODO(b/146218515) should be framework-system-stubs ], - visibility: ["//frameworks/base/apex/appsearch:__subpackages__"], + visibility: [ + "//frameworks/base/apex/appsearch:__subpackages__", + // TODO(b/146218515) remove this when framework is built with the stub of appsearch + "//frameworks/base", + ], apex_available: ["com.android.appsearch"], } +metalava_appsearch_docs_args = + "--hide-package com.android.server " + + "--error UnhiddenSystemApi " + + "--hide RequiresPermission " + + "--hide MissingPermission " + + "--hide BroadcastBehavior " + + "--hide HiddenSuperclass " + + "--hide DeprecationMismatch " + + "--hide UnavailableSymbol " + + "--hide SdkConstant " + + "--hide HiddenTypeParameter " + + "--hide Todo --hide Typo " + + "--hide HiddenTypedefConstant " + + "--show-annotation android.annotation.SystemApi " + droidstubs { name: "framework-appsearch-stubs-srcs", srcs: [ @@ -43,8 +62,9 @@ droidstubs { aidl: { include_dirs: ["frameworks/base/core/java"], }, - defaults: ["framework-module-stubs-defaults-systemapi"], - sdk_version: "system_current", + args: metalava_appsearch_docs_args, + sdk_version: "core_current", + libs: ["android_system_stubs_current"], } java_library { @@ -55,6 +75,7 @@ java_library { "java", ], }, - sdk_version: "system_current", + sdk_version: "core_current", + libs: ["android_system_stubs_current"], installable: false, } diff --git a/apex/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp index e7abcd9a645a..8aed5d04a32b 100644 --- a/apex/appsearch/service/Android.bp +++ b/apex/appsearch/service/Android.bp @@ -20,7 +20,6 @@ java_library { libs: [ "framework", "services.core", - "framework-appsearch", ], static_libs: [ "icing-java-proto-lite", diff --git a/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING new file mode 100644 index 000000000000..8fbfb1daaf6f --- /dev/null +++ b/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING @@ -0,0 +1,22 @@ +{ + "presubmit": [ + { + "name": "FrameworksMockingServicesTests", + "file_patterns": [ + "DeviceIdleController\\.java" + ], + "options": [ + {"include-filter": "com.android.server.DeviceIdleControllerTest"}, + {"exclude-annotation": "androidx.test.filters.FlakyTest"} + ] + } + ], + "postsubmit": [ + { + "name": "FrameworksMockingServicesTests", + "options": [ + {"include-filter": "com.android.server"} + ] + } + ] +}
\ No newline at end of file diff --git a/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING new file mode 100644 index 000000000000..bc7a7d3bef7d --- /dev/null +++ b/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING @@ -0,0 +1,19 @@ +{ + "presubmit": [ + { + "name": "FrameworksMockingServicesTests", + "options": [ + {"include-filter": "com.android.server.DeviceIdleControllerTest"}, + {"exclude-annotation": "androidx.test.filters.FlakyTest"} + ] + } + ], + "postsubmit": [ + { + "name": "FrameworksMockingServicesTests", + "options": [ + {"include-filter": "com.android.server"} + ] + } + ] +}
\ No newline at end of file diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java index 82292cfeea09..b9df30aa4d95 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java @@ -17,7 +17,7 @@ package com.android.server.usage; import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT; -import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED; +import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_USER; import static android.app.usage.UsageStatsManager.REASON_MAIN_MASK; import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED; import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE; @@ -441,7 +441,7 @@ public class AppIdleHistory { elapsedRealtime, true); if (idle) { appUsageHistory.currentBucket = STANDBY_BUCKET_RARE; - appUsageHistory.bucketingReason = REASON_MAIN_FORCED; + appUsageHistory.bucketingReason = REASON_MAIN_FORCED_BY_USER; } else { appUsageHistory.currentBucket = STANDBY_BUCKET_ACTIVE; // This is to pretend that the app was just used, don't freeze the state anymore. diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java index 58eb58961ac4..eb0b54b1d9fc 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -17,7 +17,8 @@ package com.android.server.usage; import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT; -import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED; +import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM; +import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_USER; import static android.app.usage.UsageStatsManager.REASON_MAIN_MASK; import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED; import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT; @@ -565,7 +566,7 @@ public class AppStandbyController implements AppStandbyInternal { // If the bucket was forced by the user/developer, leave it alone. // A usage event will be the only way to bring it out of this forced state - if (oldMainReason == REASON_MAIN_FORCED) { + if (oldMainReason == REASON_MAIN_FORCED_BY_USER) { return; } final int oldBucket = app.currentBucket; @@ -783,7 +784,7 @@ public class AppStandbyController implements AppStandbyInternal { // Inform listeners if necessary if (previouslyIdle != stillIdle) { maybeInformListeners(packageName, userId, elapsedRealtime, standbyBucket, - REASON_MAIN_FORCED, false); + REASON_MAIN_FORCED_BY_USER, false); if (!stillIdle) { notifyBatteryStats(packageName, userId, idle); } @@ -1030,8 +1031,17 @@ public class AppStandbyController implements AppStandbyInternal { callingPid, callingUid, userId, false, true, "setAppStandbyBucket", null); final boolean shellCaller = callingUid == Process.ROOT_UID || callingUid == Process.SHELL_UID; - final boolean systemCaller = UserHandle.isCore(callingUid); - final int reason = systemCaller ? REASON_MAIN_FORCED : REASON_MAIN_PREDICTED; + final int reason; + // The Settings app runs in the system UID but in a separate process. Assume + // things coming from other processes are due to the user. + if ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && callingPid != Process.myPid()) + || shellCaller) { + reason = REASON_MAIN_FORCED_BY_USER; + } else if (UserHandle.isCore(callingUid)) { + reason = REASON_MAIN_FORCED_BY_SYSTEM; + } else { + reason = REASON_MAIN_PREDICTED; + } final int packageFlags = PackageManager.MATCH_ANY_USER | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.MATCH_DIRECT_BOOT_AWARE; @@ -1087,7 +1097,11 @@ public class AppStandbyController implements AppStandbyInternal { } // If the bucket was forced, don't allow prediction to override - if ((app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED && predicted) return; + if (predicted + && ((app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_USER + || (app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_SYSTEM)) { + return; + } // If the bucket is required to stay in a higher state for a specified duration, don't // override unless the duration has passed diff --git a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING new file mode 100644 index 000000000000..cf70878b8899 --- /dev/null +++ b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING @@ -0,0 +1,19 @@ +{ + "presubmit": [ + { + "name": "FrameworksServicesTests", + "options": [ + {"include-filter": "com.android.server.usage"}, + {"exclude-annotation": "androidx.test.filters.FlakyTest"} + ] + } + ], + "postsubmit": [ + { + "name": "FrameworksServicesTests", + "options": [ + {"include-filter": "com.android.server.usage"} + ] + } + ] +}
\ No newline at end of file diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java index 0f981e25b37a..bbb87ab6ce7c 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java @@ -714,60 +714,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - private void addNetworkStats( - int tag, List<StatsLogEventWrapper> ret, NetworkStats stats, boolean withFGBG) { - int size = stats.size(); - long elapsedNanos = SystemClock.elapsedRealtimeNanos(); - long wallClockNanos = SystemClock.currentTimeMicro() * 1000L; - NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling - for (int j = 0; j < size; j++) { - stats.getValues(j, entry); - StatsLogEventWrapper e = new StatsLogEventWrapper(tag, elapsedNanos, wallClockNanos); - e.writeInt(entry.uid); - if (withFGBG) { - e.writeInt(entry.set); - } - e.writeLong(entry.rxBytes); - e.writeLong(entry.rxPackets); - e.writeLong(entry.txBytes); - e.writeLong(entry.txPackets); - ret.add(e); - } - } - - /** - * Allows rollups per UID but keeping the set (foreground/background) slicing. - * Adapted from groupedByUid in frameworks/base/core/java/android/net/NetworkStats.java - */ - private NetworkStats rollupNetworkStatsByFGBG(NetworkStats stats) { - final NetworkStats ret = new NetworkStats(stats.getElapsedRealtime(), 1); - - final NetworkStats.Entry entry = new NetworkStats.Entry(); - entry.iface = NetworkStats.IFACE_ALL; - entry.tag = NetworkStats.TAG_NONE; - entry.metered = NetworkStats.METERED_ALL; - entry.roaming = NetworkStats.ROAMING_ALL; - - int size = stats.size(); - NetworkStats.Entry recycle = new NetworkStats.Entry(); // Used for retrieving values - for (int i = 0; i < size; i++) { - stats.getValues(i, recycle); - - // Skip specific tags, since already counted in TAG_NONE - if (recycle.tag != NetworkStats.TAG_NONE) continue; - - entry.set = recycle.set; // Allows slicing by background/foreground - entry.uid = recycle.uid; - entry.rxBytes = recycle.rxBytes; - entry.rxPackets = recycle.rxPackets; - entry.txBytes = recycle.txBytes; - entry.txPackets = recycle.txPackets; - // Operations purposefully omitted since we don't use them for statsd. - ret.combineValues(entry); - } - return ret; - } - /** * Helper method to extract the Parcelable controller info from a * SynchronousResultReceiver. @@ -815,94 +761,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - private void pullWifiBytesTransferByFgBg( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - long token = Binder.clearCallingIdentity(); - try { - BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); - String[] ifaces = bs.getWifiIfaces(); - if (ifaces.length == 0) { - return; - } - if (mNetworkStatsService == null) { - Slog.e(TAG, "NetworkStats Service is not available!"); - return; - } - NetworkStats stats = rollupNetworkStatsByFGBG( - mNetworkStatsService.getDetailedUidStats(ifaces)); - addNetworkStats(tagId, pulledData, stats, true); - } catch (RemoteException e) { - Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - private void pullMobileBytesTransfer( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - long token = Binder.clearCallingIdentity(); - try { - BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); - String[] ifaces = bs.getMobileIfaces(); - if (ifaces.length == 0) { - return; - } - if (mNetworkStatsService == null) { - Slog.e(TAG, "NetworkStats Service is not available!"); - return; - } - // Combine all the metrics per Uid into one record. - NetworkStats stats = mNetworkStatsService.getDetailedUidStats(ifaces).groupedByUid(); - addNetworkStats(tagId, pulledData, stats, false); - } catch (RemoteException e) { - Slog.e(TAG, "Pulling netstats for mobile bytes has error", e); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - private void pullBluetoothBytesTransfer( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - BluetoothActivityEnergyInfo info = fetchBluetoothData(); - if (info.getUidTraffic() != null) { - for (UidTraffic traffic : info.getUidTraffic()) { - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, - wallClockNanos); - e.writeInt(traffic.getUid()); - e.writeLong(traffic.getRxBytes()); - e.writeLong(traffic.getTxBytes()); - pulledData.add(e); - } - } - } - - private void pullMobileBytesTransferByFgBg( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - long token = Binder.clearCallingIdentity(); - try { - BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); - String[] ifaces = bs.getMobileIfaces(); - if (ifaces.length == 0) { - return; - } - if (mNetworkStatsService == null) { - Slog.e(TAG, "NetworkStats Service is not available!"); - return; - } - NetworkStats stats = rollupNetworkStatsByFGBG( - mNetworkStatsService.getDetailedUidStats(ifaces)); - addNetworkStats(tagId, pulledData, stats, true); - } catch (RemoteException e) { - Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e); - } finally { - Binder.restoreCallingIdentity(token); - } - } - private void pullCpuTimePerFreq( int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { @@ -1052,33 +910,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - private void pullBluetoothActivityInfo( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - BluetoothActivityEnergyInfo info = fetchBluetoothData(); - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); - e.writeLong(info.getTimeStamp()); - e.writeInt(info.getBluetoothStackState()); - e.writeLong(info.getControllerTxTimeMillis()); - e.writeLong(info.getControllerRxTimeMillis()); - e.writeLong(info.getControllerIdleTimeMillis()); - e.writeLong(info.getControllerEnergyUsed()); - pulledData.add(e); - } - - private synchronized BluetoothActivityEnergyInfo fetchBluetoothData() { - final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - if (adapter != null) { - SynchronousResultReceiver bluetoothReceiver = new SynchronousResultReceiver( - "bluetooth"); - adapter.requestControllerActivityEnergyInfo(bluetoothReceiver); - return awaitControllerInfo(bluetoothReceiver); - } else { - Slog.e(TAG, "Failed to get bluetooth adapter!"); - return null; - } - } - private void pullSystemElapsedRealtime( int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { @@ -1671,21 +1502,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - private void pullPowerProfile( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - PowerProfile powerProfile = new PowerProfile(mContext); - Objects.requireNonNull(powerProfile); - - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, - wallClockNanos); - ProtoOutputStream proto = new ProtoOutputStream(); - powerProfile.dumpDebug(proto); - proto.flush(); - e.writeStorage(proto.getBytes()); - pulledData.add(e); - } - private void pullBuildInformation(int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); @@ -2291,26 +2107,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { long elapsedNanos = SystemClock.elapsedRealtimeNanos(); long wallClockNanos = SystemClock.currentTimeMicro() * 1000L; switch (tagId) { - - case StatsLog.MOBILE_BYTES_TRANSFER: { - pullMobileBytesTransfer(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - - case StatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: { - pullWifiBytesTransferByFgBg(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - - case StatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: { - pullMobileBytesTransferByFgBg(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - - case StatsLog.BLUETOOTH_BYTES_TRANSFER: { - pullBluetoothBytesTransfer(tagId, elapsedNanos, wallClockNanos, ret); - break; - } case StatsLog.KERNEL_WAKELOCK: { pullKernelWakelock(tagId, elapsedNanos, wallClockNanos, ret); @@ -2352,11 +2148,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { break; } - case StatsLog.BLUETOOTH_ACTIVITY_INFO: { - pullBluetoothActivityInfo(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - case StatsLog.SYSTEM_UPTIME: { pullSystemUpTime(tagId, elapsedNanos, wallClockNanos, ret); break; @@ -2455,11 +2246,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { break; } - case StatsLog.POWER_PROFILE: { - pullPowerProfile(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - case StatsLog.BUILD_INFORMATION: { pullBuildInformation(tagId, elapsedNanos, wallClockNanos, ret); break; diff --git a/api/current.txt b/api/current.txt index 16a9e49da032..afbb427ed288 100644 --- a/api/current.txt +++ b/api/current.txt @@ -30507,6 +30507,7 @@ package android.net.wifi { method @Nullable public java.security.cert.X509Certificate[] getCaCertificates(); method public java.security.cert.X509Certificate getClientCertificate(); method @Nullable public java.security.cert.X509Certificate[] getClientCertificateChain(); + method @Nullable public java.security.PrivateKey getClientPrivateKey(); method public String getDomainSuffixMatch(); method public int getEapMethod(); method public String getIdentity(); @@ -39205,6 +39206,7 @@ package android.provider { method @NonNull public static android.app.PendingIntent createWriteRequest(@NonNull android.content.ContentResolver, @NonNull java.util.Collection<android.net.Uri>); method @Nullable public static android.net.Uri getDocumentUri(@NonNull android.content.Context, @NonNull android.net.Uri); method @NonNull public static java.util.Set<java.lang.String> getExternalVolumeNames(@NonNull android.content.Context); + method public static long getGeneration(@NonNull android.content.Context, @NonNull String); method public static android.net.Uri getMediaScannerUri(); method @Nullable public static android.net.Uri getMediaUri(@NonNull android.content.Context, @NonNull android.net.Uri); method @NonNull public static java.util.Set<java.lang.String> getRecentExternalVolumeNames(@NonNull android.content.Context); @@ -39515,6 +39517,7 @@ package android.provider { field public static final String DISPLAY_NAME = "_display_name"; field public static final String DOCUMENT_ID = "document_id"; field public static final String DURATION = "duration"; + field public static final String GENERATION = "generation"; field public static final String GENRE = "genre"; field public static final String HEIGHT = "height"; field public static final String INSTANCE_ID = "instance_id"; @@ -54822,6 +54825,7 @@ package android.view.inputmethod { public final class InlineSuggestionsRequest implements android.os.Parcelable { method public int describeContents(); + method @NonNull public String getHostPackageName(); method public int getMaxSuggestionCount(); method @NonNull public java.util.List<android.view.inline.InlinePresentationSpec> getPresentationSpecs(); method public void writeToParcel(@NonNull android.os.Parcel, int); diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt index d802177e249b..0a6706550074 100644 --- a/api/module-lib-current.txt +++ b/api/module-lib-current.txt @@ -1 +1,81 @@ // Signature format: 2.0 +package android.app.timedetector { + + public final class PhoneTimeSuggestion implements android.os.Parcelable { + method public void addDebugInfo(@NonNull String); + method public void addDebugInfo(@NonNull java.util.List<java.lang.String>); + method public int describeContents(); + method @NonNull public java.util.List<java.lang.String> getDebugInfo(); + method public int getPhoneId(); + method @Nullable public android.os.TimestampedValue<java.lang.Long> getUtcTime(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.app.timedetector.PhoneTimeSuggestion> CREATOR; + } + + public static final class PhoneTimeSuggestion.Builder { + ctor public PhoneTimeSuggestion.Builder(int); + method @NonNull public android.app.timedetector.PhoneTimeSuggestion.Builder addDebugInfo(@NonNull String); + method @NonNull public android.app.timedetector.PhoneTimeSuggestion build(); + method @NonNull public android.app.timedetector.PhoneTimeSuggestion.Builder setUtcTime(@Nullable android.os.TimestampedValue<java.lang.Long>); + } + + public class TimeDetector { + method @RequiresPermission("android.permission.SUGGEST_PHONE_TIME_AND_ZONE") public void suggestPhoneTime(@NonNull android.app.timedetector.PhoneTimeSuggestion); + } + +} + +package android.app.timezonedetector { + + public final class PhoneTimeZoneSuggestion implements android.os.Parcelable { + method public void addDebugInfo(@NonNull String); + method public void addDebugInfo(@NonNull java.util.List<java.lang.String>); + method @NonNull public static android.app.timezonedetector.PhoneTimeZoneSuggestion createEmptySuggestion(int, @NonNull String); + method public int describeContents(); + method @NonNull public java.util.List<java.lang.String> getDebugInfo(); + method public int getMatchType(); + method public int getPhoneId(); + method public int getQuality(); + method @Nullable public String getZoneId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.app.timezonedetector.PhoneTimeZoneSuggestion> CREATOR; + field public static final int MATCH_TYPE_EMULATOR_ZONE_ID = 4; // 0x4 + field public static final int MATCH_TYPE_NA = 0; // 0x0 + field public static final int MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET = 3; // 0x3 + field public static final int MATCH_TYPE_NETWORK_COUNTRY_ONLY = 2; // 0x2 + field public static final int MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY = 5; // 0x5 + field public static final int QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS = 3; // 0x3 + field public static final int QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET = 2; // 0x2 + field public static final int QUALITY_NA = 0; // 0x0 + field public static final int QUALITY_SINGLE_ZONE = 1; // 0x1 + } + + public static final class PhoneTimeZoneSuggestion.Builder { + ctor public PhoneTimeZoneSuggestion.Builder(int); + method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder addDebugInfo(@NonNull String); + method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion build(); + method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder setMatchType(int); + method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder setQuality(int); + method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder setZoneId(@Nullable String); + } + + public class TimeZoneDetector { + method @RequiresPermission("android.permission.SUGGEST_PHONE_TIME_AND_ZONE") public void suggestPhoneTimeZone(@NonNull android.app.timezonedetector.PhoneTimeZoneSuggestion); + } + +} + +package android.os { + + public final class TimestampedValue<T> implements android.os.Parcelable { + ctor public TimestampedValue(long, @Nullable T); + method public int describeContents(); + method public long getReferenceTimeMillis(); + method @Nullable public T getValue(); + method public static long referenceTimeDifference(@NonNull android.os.TimestampedValue<?>, @NonNull android.os.TimestampedValue<?>); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.os.TimestampedValue<?>> CREATOR; + } + +} + diff --git a/api/system-current.txt b/api/system-current.txt index ee2e10072034..71d1a381ec31 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -208,6 +208,7 @@ package android { field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES"; field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"; field public static final String SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON = "android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON"; + field public static final String SUGGEST_PHONE_TIME_AND_ZONE = "android.permission.SUGGEST_PHONE_TIME_AND_ZONE"; field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS"; field public static final String SYSTEM_CAMERA = "android.permission.SYSTEM_CAMERA"; field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED"; @@ -327,6 +328,7 @@ package android.app { method public void setDeviceLocales(@NonNull android.os.LocaleList); method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public static void setPersistentVrThread(int); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean switchUser(@NonNull android.os.UserHandle); + method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String); } public static interface ActivityManager.OnUidImportanceListener { @@ -1714,6 +1716,7 @@ package android.content { field public static final String NETD_SERVICE = "netd"; field public static final String NETWORK_POLICY_SERVICE = "netpolicy"; field public static final String NETWORK_SCORE_SERVICE = "network_score"; + field public static final String NETWORK_STACK_SERVICE = "network_stack"; field public static final String OEM_LOCK_SERVICE = "oem_lock"; field public static final String PERMISSION_SERVICE = "permission"; field public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block"; @@ -4686,10 +4689,30 @@ package android.media.tv.tuner { package android.media.tv.tuner.filter { + public abstract class FilterConfiguration { + field public static final int FILTER_TYPE_ALP = 16; // 0x10 + field public static final int FILTER_TYPE_IP = 4; // 0x4 + field public static final int FILTER_TYPE_MMTP = 2; // 0x2 + field public static final int FILTER_TYPE_TLV = 8; // 0x8 + field public static final int FILTER_TYPE_TS = 1; // 0x1 + } + public abstract class FilterEvent { ctor public FilterEvent(); } + public class PesSettings extends android.media.tv.tuner.filter.Settings { + method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.PesSettings.Builder builder(@NonNull android.content.Context, int); + method public int getStreamId(); + method public boolean isRaw(); + } + + public static class PesSettings.Builder { + method @NonNull public android.media.tv.tuner.filter.PesSettings build(); + method @NonNull public android.media.tv.tuner.filter.PesSettings.Builder setRaw(boolean); + method @NonNull public android.media.tv.tuner.filter.PesSettings.Builder setStreamId(int); + } + public class SectionEvent extends android.media.tv.tuner.filter.FilterEvent { method public int getDataLength(); method public int getSectionNumber(); @@ -4697,6 +4720,22 @@ package android.media.tv.tuner.filter { method public int getVersion(); } + public abstract class Settings { + } + + public class TsFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration { + method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.TsFilterConfiguration.Builder builder(@NonNull android.content.Context); + method @Nullable public android.media.tv.tuner.filter.Settings getSettings(); + method public int getTpid(); + method public int getType(); + } + + public static class TsFilterConfiguration.Builder { + method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration build(); + method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration.Builder setSettings(@NonNull android.media.tv.tuner.filter.Settings); + method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration.Builder setTpid(int); + } + } package android.metrics { @@ -4779,6 +4818,7 @@ package android.net { field public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0 field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb + field public static final int TYPE_NONE = -1; // 0xffffffff } public abstract static class ConnectivityManager.OnStartTetheringCallback { @@ -4914,12 +4954,36 @@ package android.net { field @NonNull public static final android.os.Parcelable.Creator<android.net.MatchAllNetworkSpecifier> CREATOR; } + public final class NattKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable { + ctor public NattKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[]) throws android.net.InvalidPacketException; + method public int describeContents(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.NattKeepalivePacketData> CREATOR; + } + public class Network implements android.os.Parcelable { ctor public Network(@NonNull android.net.Network); method @NonNull public android.net.Network getPrivateDnsBypassingCopy(); field public final int netId; } + public final class NetworkAgentConfig implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public String getSubscriberId(); + method public boolean isNat64DetectionEnabled(); + method public boolean isProvisioningNotificationEnabled(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkAgentConfig> CREATOR; + } + + public static class NetworkAgentConfig.Builder { + ctor public NetworkAgentConfig.Builder(); + method @NonNull public android.net.NetworkAgentConfig build(); + method @NonNull public android.net.NetworkAgentConfig.Builder disableNat64Detection(); + method @NonNull public android.net.NetworkAgentConfig.Builder disableProvisioningNotification(); + method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String); + } + public final class NetworkCapabilities implements android.os.Parcelable { method public boolean deduceRestrictedCapability(); method @NonNull public int[] getTransportTypes(); @@ -4978,6 +5042,9 @@ package android.net { field @Deprecated public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore"; field public static final String EXTRA_NEW_SCORER = "newScorer"; field @Deprecated public static final String EXTRA_PACKAGE_NAME = "packageName"; + field public static final int SCORE_FILTER_CURRENT_NETWORK = 1; // 0x1 + field public static final int SCORE_FILTER_NONE = 0; // 0x0 + field public static final int SCORE_FILTER_SCAN_RESULTS = 2; // 0x2 } public static interface NetworkScoreManager.NetworkScoreCallback { @@ -5855,6 +5922,7 @@ package android.net.wifi { } public class ScanResult implements android.os.Parcelable { + ctor public ScanResult(); field public static final int CIPHER_CCMP = 3; // 0x3 field public static final int CIPHER_GCMP_256 = 4; // 0x4 field public static final int CIPHER_NONE = 0; // 0x0 @@ -5971,6 +6039,7 @@ package android.net.wifi { method @Deprecated public static boolean isMetered(@Nullable android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiInfo); method @Deprecated public boolean isNoInternetAccessExpected(); method @Deprecated public void setIpConfiguration(@Nullable android.net.IpConfiguration); + method @Deprecated public void setNetworkSelectionStatus(@NonNull android.net.wifi.WifiConfiguration.NetworkSelectionStatus); method @Deprecated public void setProxy(@NonNull android.net.IpConfiguration.ProxySettings, @NonNull android.net.ProxyInfo); field @Deprecated public static final int AP_BAND_2GHZ = 0; // 0x0 field @Deprecated public static final int AP_BAND_5GHZ = 1; // 0x1 @@ -6015,6 +6084,7 @@ package android.net.wifi { method @Deprecated public boolean getHasEverConnected(); method @Deprecated @Nullable public static String getNetworkDisableReasonString(int); method @Deprecated public int getNetworkSelectionDisableReason(); + method @Deprecated public int getNetworkSelectionStatus(); method @Deprecated @NonNull public String getNetworkStatusString(); method @Deprecated public boolean isNetworkEnabled(); method @Deprecated public boolean isNetworkPermanentlyDisabled(); @@ -6029,6 +6099,16 @@ package android.net.wifi { field @Deprecated public static final int DISABLED_NO_INTERNET_TEMPORARY = 4; // 0x4 field @Deprecated public static final int NETWORK_SELECTION_DISABLED_MAX = 10; // 0xa field @Deprecated public static final int NETWORK_SELECTION_ENABLE = 0; // 0x0 + field @Deprecated public static final int NETWORK_SELECTION_ENABLED = 0; // 0x0 + field @Deprecated public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED = 2; // 0x2 + field @Deprecated public static final int NETWORK_SELECTION_TEMPORARY_DISABLED = 1; // 0x1 + } + + @Deprecated public static final class WifiConfiguration.NetworkSelectionStatus.Builder { + ctor @Deprecated public WifiConfiguration.NetworkSelectionStatus.Builder(); + method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus build(); + method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus.Builder setNetworkSelectionDisableReason(int); + method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus.Builder setNetworkSelectionStatus(int); } @Deprecated public static class WifiConfiguration.RecentFailure { @@ -6073,6 +6153,15 @@ package android.net.wifi { field public static final int INVALID_RSSI = -127; // 0xffffff81 } + public static final class WifiInfo.Builder { + ctor public WifiInfo.Builder(); + method @NonNull public android.net.wifi.WifiInfo build(); + method @NonNull public android.net.wifi.WifiInfo.Builder setBssid(@NonNull String); + method @NonNull public android.net.wifi.WifiInfo.Builder setNetworkId(int); + method @NonNull public android.net.wifi.WifiInfo.Builder setRssi(int); + method @NonNull public android.net.wifi.WifiInfo.Builder setSsid(@NonNull byte[]); + } + public class WifiManager { method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoin(int, boolean); @@ -10368,9 +10457,15 @@ package android.telephony { method public boolean disableCellBroadcastRange(int, int, int); method public boolean enableCellBroadcastRange(int, int, int); method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_MESSAGES_ON_ICC) public java.util.List<android.telephony.SmsMessage> getMessagesFromIcc(); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getPremiumSmsConsent(@NonNull String); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSmsCapacityOnIcc(); method public void sendMultipartTextMessage(@NonNull String, @NonNull String, @NonNull java.util.List<java.lang.String>, @Nullable java.util.List<android.app.PendingIntent>, @Nullable java.util.List<android.app.PendingIntent>, @NonNull String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void sendMultipartTextMessageWithoutPersisting(String, String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPremiumSmsConsent(@NonNull String, int); + field public static final int PREMIUM_SMS_CONSENT_ALWAYS_ALLOW = 3; // 0x3 + field public static final int PREMIUM_SMS_CONSENT_ASK_USER = 1; // 0x1 + field public static final int PREMIUM_SMS_CONSENT_NEVER_ALLOW = 2; // 0x2 + field public static final int PREMIUM_SMS_CONSENT_UNKNOWN = 0; // 0x0 } public class SmsMessage { @@ -10598,6 +10693,8 @@ package android.telephony { field public static final String EXTRA_ERROR_CODE = "errorCode"; field public static final String EXTRA_PCO_ID = "pcoId"; field public static final String EXTRA_PCO_VALUE = "pcoValue"; + field public static final String EXTRA_PHONE_IN_ECM_STATE = "android.telephony.extra.PHONE_IN_ECM_STATE"; + field public static final String EXTRA_PHONE_IN_EMERGENCY_CALL = "android.telephony.extra.PHONE_IN_EMERGENCY_CALL"; field public static final String EXTRA_REDIRECTION_URL = "redirectionUrl"; field public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE"; field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL"; diff --git a/api/test-current.txt b/api/test-current.txt index 491d1eb19b86..1db4c9b82343 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -757,6 +757,7 @@ package android.content { field public static final String BUGREPORT_SERVICE = "bugreport"; field public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture"; field public static final String DEVICE_IDLE_CONTROLLER = "deviceidle"; + field public static final String NETWORK_STACK_SERVICE = "network_stack"; field public static final String PERMISSION_SERVICE = "permission"; field public static final String POWER_WHITELIST_MANAGER = "power_whitelist"; field public static final String ROLLBACK_SERVICE = "rollback"; @@ -4278,6 +4279,7 @@ package android.util { field public static final String FFLAG_OVERRIDE_PREFIX = "sys.fflag.override."; field public static final String FFLAG_PREFIX = "sys.fflag."; field public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid"; + field public static final String NOTIF_CONVO_BYPASS_SHORTCUT_REQ = "settings_notif_convo_bypass_shortcut_req"; field public static final String PERSIST_PREFIX = "persist.sys.fflag.override."; field public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press"; field public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer"; diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 8d5b5b4f3596..1441d48771d6 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -341,7 +341,7 @@ message Atom { } // Pulled events will start at field 10000. - // Next: 10069 + // Next: 10070 oneof pulled { WifiBytesTransfer wifi_bytes_transfer = 10000; WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001; @@ -411,6 +411,7 @@ message Atom { NotificationRemoteViews notification_remote_views = 10066; DangerousPermissionStateSampled dangerous_permission_state_sampled = 10067; GraphicsStats graphics_stats = 10068; + RuntimeAppOpsAccess runtime_app_ops_access = 10069; } // DO NOT USE field numbers above 100,000 in AOSP. @@ -7086,7 +7087,7 @@ message AppOps { // Uid of the package requesting the op optional int32 uid = 1 [(is_uid) = true]; - // Nmae of the package performing the op + // Name of the package performing the op optional string package_name = 2; // operation id; maps to the OP_* constants in AppOpsManager.java @@ -7872,3 +7873,35 @@ message GraphicsStats { // more apps are running / rendering. optional bool is_today = 16; } + +/** + * Message related to dangerous (runtime) app ops access + */ +message RuntimeAppOpsAccess { + // Uid of the package accessing app op + optional int32 uid = 1 [(is_uid) = true]; + + // Name of the package accessing app op + optional string package_name = 2; + + // operation id; maps to the OP_* constants in AppOpsManager.java + optional int32 op_id = 3; + + // feature id; provided by developer when accessing related API, limited at 50 chars by API. + // Features must be provided through manifest using <feature> tag available in R and above. + optional string feature_id = 4; + + // message related to app op access, limited to 600 chars by API + optional string message = 5; + + enum SamplingStrategy { + DEFAULT = 0; + UNIFORM = 1; + RARELY_USED = 2; + } + + // sampling strategy used to collect this message + optional SamplingStrategy sampling_strategy = 6; +} + + diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index b5680331f63e..731afe8c0859 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -60,27 +60,6 @@ const int64_t NO_ALARM_UPDATE = INT64_MAX; std::map<PullerKey, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { - // wifi_bytes_transfer_by_fg_bg - {{.atomTag = android::util::WIFI_BYTES_TRANSFER_BY_FG_BG}, - {.additiveFields = {3, 4, 5, 6}, - .puller = new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)}}, - - // mobile_bytes_transfer - {{.atomTag = android::util::MOBILE_BYTES_TRANSFER}, - {.additiveFields = {2, 3, 4, 5}, - .puller = new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER)}}, - - // mobile_bytes_transfer_by_fg_bg - {{.atomTag = android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG}, - {.additiveFields = {3, 4, 5, 6}, - .puller = - new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)}}, - - // bluetooth_bytes_transfer - {{.atomTag = android::util::BLUETOOTH_BYTES_TRANSFER}, - {.additiveFields = {2, 3}, - .puller = new StatsCompanionServicePuller(android::util::BLUETOOTH_BYTES_TRANSFER)}}, - // kernel_wakelock {{.atomTag = android::util::KERNEL_WAKELOCK}, {.puller = new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}}, @@ -132,10 +111,6 @@ std::map<PullerKey, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { {{.atomTag = android::util::MODEM_ACTIVITY_INFO}, {.puller = new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}}, - // bluetooth_activity_info - {{.atomTag = android::util::BLUETOOTH_ACTIVITY_INFO}, - {.puller = new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}}, - // system_elapsed_realtime {{.atomTag = android::util::SYSTEM_ELAPSED_REALTIME}, {.coolDownNs = NS_PER_SEC, @@ -249,10 +224,6 @@ std::map<PullerKey, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { .coolDownNs = 3 * NS_PER_SEC, .puller = new StatsCompanionServicePuller(android::util::DISK_IO)}}, - // PowerProfile constants for power model calculations. - {{.atomTag = android::util::POWER_PROFILE}, - {.puller = new StatsCompanionServicePuller(android::util::POWER_PROFILE)}}, - // Process cpu stats. Min cool-down is 5 sec, inline with what AcitivityManagerService uses. {{.atomTag = android::util::PROCESS_CPU_TIME}, {.coolDownNs = 5 * NS_PER_SEC /* min cool-down in seconds*/, diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index 8fe2f12a1023..f2702a864c2f 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -25,6 +25,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.Size; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.UserHandleAware; import android.app.Activity; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; @@ -40,6 +41,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Parcelable; +import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.text.TextUtils; @@ -528,12 +530,9 @@ public class AccountManager { * authenticator known to the AccountManager service. Empty (never * null) if no authenticators are known. */ + @UserHandleAware public AuthenticatorDescription[] getAuthenticatorTypes() { - try { - return mService.getAuthenticatorTypes(UserHandle.getCallingUserId()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getAuthenticatorTypesAsUser(mContext.getUserId()); } /** @@ -584,13 +583,10 @@ public class AccountManager { * @return An array of {@link Account}, one for each account. Empty (never null) if no accounts * have been added. */ + @UserHandleAware @NonNull public Account[] getAccounts() { - try { - return mService.getAccounts(null, mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getAccountsAsUser(mContext.getUserId()); } /** @@ -708,6 +704,7 @@ public class AccountManager { * @return An array of {@link Account}, one per matching account. Empty (never null) if no * accounts of the specified type have been added. */ + @UserHandleAware @NonNull public Account[] getAccountsByType(String type) { return getAccountsByTypeAsUser(type, mContext.getUser()); @@ -1183,23 +1180,11 @@ public class AccountManager { * {@link #removeAccount(Account, Activity, AccountManagerCallback, Handler)} * instead */ + @UserHandleAware @Deprecated public AccountManagerFuture<Boolean> removeAccount(final Account account, AccountManagerCallback<Boolean> callback, Handler handler) { - if (account == null) throw new IllegalArgumentException("account is null"); - return new Future2Task<Boolean>(handler, callback) { - @Override - public void doWork() throws RemoteException { - mService.removeAccount(mResponse, account, false); - } - @Override - public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException { - if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) { - throw new AuthenticatorException("no result in response"); - } - return bundle.getBoolean(KEY_BOOLEAN_RESULT); - } - }.start(); + return removeAccountAsUser(account, callback, handler, mContext.getUser()); } /** @@ -1243,15 +1228,10 @@ public class AccountManager { * adding accounts (of this type) has been disabled by policy * </ul> */ + @UserHandleAware public AccountManagerFuture<Bundle> removeAccount(final Account account, final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) { - if (account == null) throw new IllegalArgumentException("account is null"); - return new AmsTask(activity, handler, callback) { - @Override - public void doWork() throws RemoteException { - mService.removeAccount(mResponse, account, activity != null); - } - }.start(); + return removeAccountAsUser(account, activity, callback, handler, mContext.getUser()); } /** @@ -1841,24 +1821,30 @@ public class AccountManager { * creating a new account, usually because of network trouble * </ul> */ + @UserHandleAware public AccountManagerFuture<Bundle> addAccount(final String accountType, final String authTokenType, final String[] requiredFeatures, final Bundle addAccountOptions, final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) { - if (accountType == null) throw new IllegalArgumentException("accountType is null"); - final Bundle optionsIn = new Bundle(); - if (addAccountOptions != null) { - optionsIn.putAll(addAccountOptions); - } - optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName()); - - return new AmsTask(activity, handler, callback) { - @Override - public void doWork() throws RemoteException { - mService.addAccount(mResponse, accountType, authTokenType, - requiredFeatures, activity != null, optionsIn); + if (Process.myUserHandle().equals(mContext.getUser())) { + if (accountType == null) throw new IllegalArgumentException("accountType is null"); + final Bundle optionsIn = new Bundle(); + if (addAccountOptions != null) { + optionsIn.putAll(addAccountOptions); } - }.start(); + optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName()); + + return new AmsTask(activity, handler, callback) { + @Override + public void doWork() throws RemoteException { + mService.addAccount(mResponse, accountType, authTokenType, + requiredFeatures, activity != null, optionsIn); + } + }.start(); + } else { + return addAccountAsUser(accountType, authTokenType, requiredFeatures, addAccountOptions, + activity, callback, handler, mContext.getUser()); + } } /** @@ -2002,6 +1988,7 @@ public class AccountManager { * verifying the password, usually because of network trouble * </ul> */ + @UserHandleAware public AccountManagerFuture<Bundle> confirmCredentials(final Account account, final Bundle options, final Activity activity, @@ -3209,6 +3196,7 @@ public class AccountManager { * </ul> * @see #startAddAccountSession and #startUpdateCredentialsSession */ + @UserHandleAware public AccountManagerFuture<Bundle> finishSession( final Bundle sessionBundle, final Activity activity, diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl index 012713891d11..ce68e082cf4f 100644 --- a/core/java/android/accounts/IAccountManager.aidl +++ b/core/java/android/accounts/IAccountManager.aidl @@ -34,7 +34,6 @@ interface IAccountManager { String getPassword(in Account account); String getUserData(in Account account, String key); AuthenticatorDescription[] getAuthenticatorTypes(int userId); - Account[] getAccounts(String accountType, String opPackageName); Account[] getAccountsForPackage(String packageName, int uid, String opPackageName); Account[] getAccountsByTypeForPackage(String type, String packageName, String opPackageName); Account[] getAccountsAsUser(String accountType, int userId, String opPackageName); @@ -45,8 +44,6 @@ interface IAccountManager { void getAccountsByFeatures(in IAccountManagerResponse response, String accountType, in String[] features, String opPackageName); boolean addAccountExplicitly(in Account account, String password, in Bundle extras); - void removeAccount(in IAccountManagerResponse response, in Account account, - boolean expectActivityLaunch); void removeAccountAsUser(in IAccountManagerResponse response, in Account account, boolean expectActivityLaunch, int userId); boolean removeAccountExplicitly(in Account account); diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 9aef20b29490..c3b07c8644da 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -4073,6 +4073,29 @@ public class ActivityManager { } /** + * Updates mcc mnc configuration and applies changes to the entire system. + * + * @param mcc mcc configuration to update. + * @param mnc mnc configuration to update. + * @throws RemoteException; IllegalArgumentException if mcc or mnc is null; + * @return Returns {@code true} if the configuration was updated successfully; + * {@code false} otherwise. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) + public boolean updateMccMncConfiguration(@NonNull String mcc, @NonNull String mnc) { + if (mcc == null || mnc == null) { + throw new IllegalArgumentException("mcc or mnc cannot be null."); + } + try { + return getService().updateMccMncConfiguration(mcc, mnc); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Logs out current current foreground user by switching to the system user and stopping the * user being switched from. * @hide diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index e8494c4c5893..bd6baec30be0 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -188,6 +188,16 @@ interface IActivityManager { */ @UnsupportedAppUsage boolean updateConfiguration(in Configuration values); + /** + * Updates mcc mnc configuration and applies changes to the entire system. + * + * @param mcc mcc configuration to update. + * @param mnc mnc configuration to update. + * @throws RemoteException; IllegalArgumentException if mcc or mnc is null. + * @return Returns {@code true} if the configuration was updated; + * {@code false} otherwise. + */ + boolean updateMccMncConfiguration(in String mcc, in String mnc); boolean stopServiceToken(in ComponentName className, in IBinder token, int startId); @UnsupportedAppUsage void setProcessLimit(int max); diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 96664ebd87bd..a9be9ea33089 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -346,6 +346,14 @@ public final class SystemServiceRegistry { } }); + registerService(Context.NETWORK_STACK_SERVICE, IBinder.class, + new StaticServiceFetcher<IBinder>() { + @Override + public IBinder createService() { + return ServiceManager.getService(Context.NETWORK_STACK_SERVICE); + } + }); + registerService(Context.TETHERING_SERVICE, TetheringManager.class, new CachedServiceFetcher<TetheringManager>() { @Override diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 69640b8321d1..caaa686ecf08 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1992,16 +1992,6 @@ public class DevicePolicyManager { public static final int CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER = 14; /** - * Result code for {@link #checkProvisioningPreCondition}. - * - * <p>Returned for {@link #ACTION_PROVISION_MANAGED_PROFILE} when adding a managed profile is - * disallowed by {@link UserManager#DISALLOW_ADD_MANAGED_PROFILE}. - * - * @hide - */ - public static final int CODE_ADD_MANAGED_PROFILE_DISALLOWED = 15; - - /** * Result codes for {@link #checkProvisioningPreCondition} indicating all the provisioning pre * conditions. * @@ -2013,7 +2003,7 @@ public class DevicePolicyManager { CODE_USER_SETUP_COMPLETED, CODE_NOT_SYSTEM_USER, CODE_HAS_PAIRED, CODE_MANAGED_USERS_NOT_SUPPORTED, CODE_SYSTEM_USER, CODE_CANNOT_ADD_MANAGED_PROFILE, CODE_NOT_SYSTEM_USER_SPLIT, CODE_DEVICE_ADMIN_NOT_SUPPORTED, - CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER, CODE_ADD_MANAGED_PROFILE_DISALLOWED + CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER }) public @interface ProvisioningPreCondition {} diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.java b/core/java/android/app/timedetector/PhoneTimeSuggestion.java index 479e4b4efb4c..bd649f88f40a 100644 --- a/core/java/android/app/timedetector/PhoneTimeSuggestion.java +++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.java @@ -18,6 +18,7 @@ package android.app.timedetector; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.os.TimestampedValue; @@ -28,17 +29,23 @@ import java.util.List; import java.util.Objects; /** - * A time signal from a telephony source. The value can be {@code null} to indicate that the - * telephony source has entered an "un-opinionated" state and any previously sent suggestions are - * being withdrawn. When not {@code null}, the value consists of the number of milliseconds elapsed - * since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime clock when that number - * was established. The elapsed realtime clock is considered accurate but volatile, so time signals - * must not be persisted across device resets. + * A time suggestion from an identified telephony source. e.g. from NITZ information from a specific + * radio. + * + * <p>The time value can be {@code null} to indicate that the telephony source has entered an + * "un-opinionated" state and any previous suggestions from the source are being withdrawn. When not + * {@code null}, the value consists of the number of milliseconds elapsed since 1/1/1970 00:00:00 + * UTC and the time according to the elapsed realtime clock when that number was established. The + * elapsed realtime clock is considered accurate but volatile, so time suggestions must not be + * persisted across device resets. * * @hide */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public final class PhoneTimeSuggestion implements Parcelable { + /** @hide */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final @NonNull Parcelable.Creator<PhoneTimeSuggestion> CREATOR = new Parcelable.Creator<PhoneTimeSuggestion>() { public PhoneTimeSuggestion createFromParcel(Parcel in) { @@ -85,15 +92,27 @@ public final class PhoneTimeSuggestion implements Parcelable { dest.writeList(mDebugInfo); } + /** + * Returns an identifier for the source of this suggestion. When a device has several "phones", + * i.e. sim slots or equivalent, it is used to identify which one. + */ public int getPhoneId() { return mPhoneId; } + /** + * Returns the suggestion. {@code null} means that the caller is no longer sure what time it + * is. + */ @Nullable public TimestampedValue<Long> getUtcTime() { return mUtcTime; } + /** + * Returns debug metadata for the suggestion. The information is present in {@link #toString()} + * but is not considered for {@link #equals(Object)} and {@link #hashCode()}. + */ @NonNull public List<String> getDebugInfo() { return mDebugInfo == null @@ -105,7 +124,7 @@ public final class PhoneTimeSuggestion implements Parcelable { * information is present in {@link #toString()} but is not considered for * {@link #equals(Object)} and {@link #hashCode()}. */ - public void addDebugInfo(String debugInfo) { + public void addDebugInfo(@NonNull String debugInfo) { if (mDebugInfo == null) { mDebugInfo = new ArrayList<>(); } @@ -156,16 +175,19 @@ public final class PhoneTimeSuggestion implements Parcelable { * * @hide */ - public static class Builder { + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final class Builder { private final int mPhoneId; - private TimestampedValue<Long> mUtcTime; - private List<String> mDebugInfo; + @Nullable private TimestampedValue<Long> mUtcTime; + @Nullable private List<String> mDebugInfo; + /** Creates a builder with the specified {@code phoneId}. */ public Builder(int phoneId) { mPhoneId = phoneId; } /** Returns the builder for call chaining. */ + @NonNull public Builder setUtcTime(@Nullable TimestampedValue<Long> utcTime) { if (utcTime != null) { // utcTime can be null, but the value it holds cannot. @@ -177,6 +199,7 @@ public final class PhoneTimeSuggestion implements Parcelable { } /** Returns the builder for call chaining. */ + @NonNull public Builder addDebugInfo(@NonNull String debugInfo) { if (mDebugInfo == null) { mDebugInfo = new ArrayList<>(); @@ -186,6 +209,7 @@ public final class PhoneTimeSuggestion implements Parcelable { } /** Returns the {@link PhoneTimeSuggestion}. */ + @NonNull public PhoneTimeSuggestion build() { return new PhoneTimeSuggestion(this); } diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java index 54dd1bed5361..7c29f017c02b 100644 --- a/core/java/android/app/timedetector/TimeDetector.java +++ b/core/java/android/app/timedetector/TimeDetector.java @@ -18,6 +18,7 @@ package android.app.timedetector; import android.annotation.NonNull; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.os.RemoteException; @@ -29,8 +30,11 @@ import android.util.Log; /** * The interface through which system components can send signals to the TimeDetectorService. + * + * <p>This class is marked non-final for mockito. * @hide */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @SystemService(Context.TIME_DETECTOR_SERVICE) public class TimeDetector { private static final String TAG = "timedetector.TimeDetector"; @@ -38,6 +42,7 @@ public class TimeDetector { private final ITimeDetectorService mITimeDetectorService; + /** @hide */ public TimeDetector() throws ServiceNotFoundException { mITimeDetectorService = ITimeDetectorService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.TIME_DETECTOR_SERVICE)); @@ -62,6 +67,8 @@ public class TimeDetector { /** * Suggests the user's manually entered current time to the detector. + * + * @hide */ @RequiresPermission(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE) public void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion) { @@ -77,6 +84,8 @@ public class TimeDetector { /** * A shared utility method to create a {@link ManualTimeSuggestion}. + * + * @hide */ public static ManualTimeSuggestion createManualTimeSuggestion(long when, String why) { TimestampedValue<Long> utcTime = @@ -88,6 +97,8 @@ public class TimeDetector { /** * Suggests the time according to a network time source like NTP. + * + * @hide */ @RequiresPermission(android.Manifest.permission.SET_TIME) public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) { diff --git a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java index e8162488394c..d71ffcb9f772 100644 --- a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java +++ b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java @@ -19,6 +19,7 @@ package android.app.timezonedetector; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -30,12 +31,27 @@ import java.util.List; import java.util.Objects; /** - * A suggested time zone from a Phone-based signal, e.g. from MCC and NITZ information. + * A time zone suggestion from an identified telephony source, e.g. from MCC and NITZ information + * associated with a specific radio. + * + * <p>The time zone ID can be {@code null} to indicate that the telephony source has entered an + * "un-opinionated" state and any previous suggestions from that source are being withdrawn. + * When not {@code null}, the value consists of a suggested time zone ID and metadata that can be + * used to judge quality / certainty of the suggestion. + * + * <p>{@code matchType} must be set to {@link #MATCH_TYPE_NA} when {@code zoneId} is {@code null}, + * and one of the other {@code MATCH_TYPE_} values when it is not {@code null}. + * + * <p>{@code quality} must be set to {@link #QUALITY_NA} when {@code zoneId} is {@code null}, + * and one of the other {@code QUALITY_} values when it is not {@code null}. * * @hide */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public final class PhoneTimeZoneSuggestion implements Parcelable { + /** @hide */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @NonNull public static final Creator<PhoneTimeZoneSuggestion> CREATOR = new Creator<PhoneTimeZoneSuggestion>() { @@ -58,6 +74,7 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { return new Builder(phoneId).addDebugInfo(debugInfo).build(); } + /** @hide */ @IntDef({ MATCH_TYPE_NA, MATCH_TYPE_NETWORK_COUNTRY_ONLY, MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, MATCH_TYPE_EMULATOR_ZONE_ID, MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY }) @Retention(RetentionPolicy.SOURCE) @@ -90,6 +107,7 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { */ public static final int MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY = 5; + /** @hide */ @IntDef({ QUALITY_NA, QUALITY_SINGLE_ZONE, QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS }) @Retention(RetentionPolicy.SOURCE) @@ -115,7 +133,7 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { /** * The ID of the phone this suggestion is associated with. For multiple-sim devices this - * helps to establish origin so filtering / stickiness can be implemented. + * helps to establish source so filtering / stickiness can be implemented. */ private final int mPhoneId; @@ -123,6 +141,7 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { * The suggestion. {@code null} means there is no current suggestion and any previous suggestion * should be forgotten. */ + @Nullable private final String mZoneId; /** @@ -139,9 +158,10 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { private final int mQuality; /** - * Free-form debug information about how the signal was derived. Used for debug only, + * Free-form debug information about how the suggestion was derived. Used for debug only, * intentionally not used in equals(), etc. */ + @Nullable private List<String> mDebugInfo; private PhoneTimeZoneSuggestion(Builder builder) { @@ -182,25 +202,47 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { return 0; } + /** + * Returns an identifier for the source of this suggestion. When a device has several "phones", + * i.e. sim slots or equivalent, it is used to identify which one. + */ public int getPhoneId() { return mPhoneId; } + /** + * Returns the suggested time zone Olson ID, e.g. "America/Los_Angeles". {@code null} means that + * the caller is no longer sure what the current time zone is. See + * {@link PhoneTimeZoneSuggestion} for the associated {@code matchType} / {@code quality} rules. + */ @Nullable public String getZoneId() { return mZoneId; } + /** + * Returns information about how the suggestion was determined which could be used to rank + * suggestions when several are available from different sources. See + * {@link PhoneTimeZoneSuggestion} for the associated rules. + */ @MatchType public int getMatchType() { return mMatchType; } + /** + * Returns information about the likelihood of the suggested zone being correct. See + * {@link PhoneTimeZoneSuggestion} for the associated rules. + */ @Quality public int getQuality() { return mQuality; } + /** + * Returns debug metadata for the suggestion. The information is present in {@link #toString()} + * but is not considered for {@link #equals(Object)} and {@link #hashCode()}. + */ @NonNull public List<String> getDebugInfo() { return mDebugInfo == null @@ -267,36 +309,43 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { * * @hide */ - public static class Builder { + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final class Builder { private final int mPhoneId; - private String mZoneId; + @Nullable private String mZoneId; @MatchType private int mMatchType; @Quality private int mQuality; - private List<String> mDebugInfo; + @Nullable private List<String> mDebugInfo; public Builder(int phoneId) { mPhoneId = phoneId; } - /** Returns the builder for call chaining. */ - public Builder setZoneId(String zoneId) { + /** + * Returns the builder for call chaining. + */ + @NonNull + public Builder setZoneId(@Nullable String zoneId) { mZoneId = zoneId; return this; } /** Returns the builder for call chaining. */ + @NonNull public Builder setMatchType(@MatchType int matchType) { mMatchType = matchType; return this; } /** Returns the builder for call chaining. */ + @NonNull public Builder setQuality(@Quality int quality) { mQuality = quality; return this; } /** Returns the builder for call chaining. */ + @NonNull public Builder addDebugInfo(@NonNull String debugInfo) { if (mDebugInfo == null) { mDebugInfo = new ArrayList<>(); @@ -333,6 +382,7 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { } /** Returns the {@link PhoneTimeZoneSuggestion}. */ + @NonNull public PhoneTimeZoneSuggestion build() { validate(); return new PhoneTimeZoneSuggestion(this); diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java index e165d8a76caa..5b5f311264e3 100644 --- a/core/java/android/app/timezonedetector/TimeZoneDetector.java +++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java @@ -18,6 +18,7 @@ package android.app.timezonedetector; import android.annotation.NonNull; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.os.RemoteException; @@ -28,8 +29,10 @@ import android.util.Log; /** * The interface through which system components can send signals to the TimeZoneDetectorService. * + * <p>This class is non-final for mockito. * @hide */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @SystemService(Context.TIME_ZONE_DETECTOR_SERVICE) public class TimeZoneDetector { private static final String TAG = "timezonedetector.TimeZoneDetector"; @@ -37,6 +40,7 @@ public class TimeZoneDetector { private final ITimeZoneDetectorService mITimeZoneDetectorService; + /** @hide */ public TimeZoneDetector() throws ServiceNotFoundException { mITimeZoneDetectorService = ITimeZoneDetectorService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.TIME_ZONE_DETECTOR_SERVICE)); @@ -46,7 +50,10 @@ public class TimeZoneDetector { * Suggests the current time zone, determined using telephony signals, to the detector. The * detector may ignore the signal based on system settings, whether better information is * available, and so on. + * + * @hide */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @RequiresPermission(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE) public void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion) { if (DEBUG) { @@ -62,6 +69,8 @@ public class TimeZoneDetector { /** * Suggests the current time zone, determined for the user's manually information, to the * detector. The detector may ignore the signal based on system settings. + * + * @hide */ @RequiresPermission(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE) public void suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) { @@ -77,6 +86,8 @@ public class TimeZoneDetector { /** * A shared utility method to create a {@link ManualTimeZoneSuggestion}. + * + * @hide */ public static ManualTimeZoneSuggestion createManualTimeZoneSuggestion(String tzId, String why) { ManualTimeZoneSuggestion suggestion = new ManualTimeZoneSuggestion(tzId); diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 176a181965ed..a60e591dd0e6 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -163,7 +163,6 @@ public final class UsageStatsManager { /** * The app spent sufficient time in the old bucket without any substantial event so it reached * the timeout threshold to have its bucket lowered. - * * @hide */ public static final int REASON_MAIN_TIMEOUT = 0x0200; @@ -173,15 +172,25 @@ public final class UsageStatsManager { */ public static final int REASON_MAIN_USAGE = 0x0300; /** - * Forced by a core UID. + * Forced by the user/developer, either explicitly or implicitly through some action. If user + * action was not involved and this is purely due to the system, + * {@link #REASON_MAIN_FORCED_BY_SYSTEM} should be used instead. * @hide */ - public static final int REASON_MAIN_FORCED = 0x0400; + public static final int REASON_MAIN_FORCED_BY_USER = 0x0400; /** - * Set by a privileged system app. + * Set by a privileged system app. This may be overridden by + * {@link #REASON_MAIN_FORCED_BY_SYSTEM} or user action. * @hide */ public static final int REASON_MAIN_PREDICTED = 0x0500; + /** + * Forced by the system, independent of user action. If user action is involved, + * {@link #REASON_MAIN_FORCED_BY_USER} should be used instead. When this is used, only + * {@link #REASON_MAIN_FORCED_BY_SYSTEM} or user action can change the bucket. + * @hide + */ + public static final int REASON_MAIN_FORCED_BY_SYSTEM = 0x0600; /** @hide */ public static final int REASON_SUB_MASK = 0x00FF; @@ -1016,7 +1025,10 @@ public final class UsageStatsManager { case REASON_MAIN_DEFAULT: sb.append("d"); break; - case REASON_MAIN_FORCED: + case REASON_MAIN_FORCED_BY_SYSTEM: + sb.append("s"); + break; + case REASON_MAIN_FORCED_BY_USER: sb.append("f"); break; case REASON_MAIN_PREDICTED: diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 1b40a184c52b..9ef95743b0c9 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3953,10 +3953,12 @@ public abstract class Context { /** * Use with {@link android.os.ServiceManager.getService()} to retrieve a - * {@link NetworkStackClient} IBinder for communicating with the network stack + * {@link INetworkStackConnector} IBinder for communicating with the network stack * @hide * @see NetworkStackClient */ + @SystemApi + @TestApi public static final String NETWORK_STACK_SERVICE = "network_stack"; /** diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 4bf3e905697d..c523f6514c54 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -517,7 +517,7 @@ public class ConnectivityManager { * The absence of a connection type. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) + @SystemApi public static final int TYPE_NONE = -1; /** @@ -3169,10 +3169,10 @@ public class ConnectivityManager { /** * @hide * Register a NetworkAgent with ConnectivityService. - * @return NetID corresponding to NetworkAgent. + * @return Network corresponding to NetworkAgent. */ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, + public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, NetworkCapabilities nc, int score, NetworkAgentConfig config) { return registerNetworkAgent(messenger, ni, lp, nc, score, config, NetworkProvider.ID_NONE); } @@ -3180,10 +3180,10 @@ public class ConnectivityManager { /** * @hide * Register a NetworkAgent with ConnectivityService. - * @return NetID corresponding to NetworkAgent. + * @return Network corresponding to NetworkAgent. */ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, + public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, NetworkCapabilities nc, int score, NetworkAgentConfig config, int providerId) { try { return mService.registerNetworkAgent(messenger, ni, lp, nc, score, config, providerId); diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 7691beba3208..186196bd31c7 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -152,7 +152,7 @@ interface IConnectivityManager void declareNetworkRequestUnfulfillable(in NetworkRequest request); - int registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, + Network registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, in NetworkCapabilities nc, int score, in NetworkAgentConfig config, in int factorySerialNumber); diff --git a/core/java/android/net/NattKeepalivePacketData.java b/core/java/android/net/NattKeepalivePacketData.java index 3fb52f12a88d..bd39c13ba092 100644 --- a/core/java/android/net/NattKeepalivePacketData.java +++ b/core/java/android/net/NattKeepalivePacketData.java @@ -16,9 +16,11 @@ package android.net; -import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; -import static android.net.SocketKeepalive.ERROR_INVALID_PORT; +import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS; +import static android.net.InvalidPacketException.ERROR_INVALID_PORT; +import android.annotation.NonNull; +import android.annotation.SystemApi; import android.net.util.IpUtils; import android.os.Parcel; import android.os.Parcelable; @@ -30,20 +32,22 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; /** @hide */ +@SystemApi public final class NattKeepalivePacketData extends KeepalivePacketData implements Parcelable { private static final int IPV4_HEADER_LENGTH = 20; private static final int UDP_HEADER_LENGTH = 8; // This should only be constructed via static factory methods, such as // nattKeepalivePacket - private NattKeepalivePacketData(InetAddress srcAddress, int srcPort, - InetAddress dstAddress, int dstPort, byte[] data) throws + public NattKeepalivePacketData(@NonNull InetAddress srcAddress, int srcPort, + @NonNull InetAddress dstAddress, int dstPort, @NonNull byte[] data) throws InvalidPacketException { super(srcAddress, srcPort, dstAddress, dstPort, data); } /** * Factory method to create Nat-T keepalive packet structure. + * @hide */ public static NattKeepalivePacketData nattKeepalivePacket( InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort) @@ -87,7 +91,7 @@ public final class NattKeepalivePacketData extends KeepalivePacketData implement } /** Write to parcel */ - public void writeToParcel(Parcel out, int flags) { + public void writeToParcel(@NonNull Parcel out, int flags) { out.writeString(srcAddress.getHostAddress()); out.writeString(dstAddress.getHostAddress()); out.writeInt(srcPort); @@ -95,7 +99,7 @@ public final class NattKeepalivePacketData extends KeepalivePacketData implement } /** Parcelable Creator */ - public static final Parcelable.Creator<NattKeepalivePacketData> CREATOR = + public static final @NonNull Parcelable.Creator<NattKeepalivePacketData> CREATOR = new Parcelable.Creator<NattKeepalivePacketData>() { public NattKeepalivePacketData createFromParcel(Parcel in) { final InetAddress srcAddress = diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index fc72eecd4145..d28620433c21 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -44,9 +44,10 @@ import java.util.concurrent.atomic.AtomicBoolean; * @hide */ public abstract class NetworkAgent { - // Guaranteed to be valid (not NETID_UNSET), otherwise registerNetworkAgent() would have thrown - // an exception. - public final int netId; + // Guaranteed to be non-null, otherwise registerNetworkAgent() would have thrown + // an exception. Be careful in tests when mocking though. + @NonNull + public final Network network; private final Handler mHandler; private volatile AsyncChannel mAsyncChannel; @@ -246,7 +247,7 @@ public abstract class NetworkAgent { if (VDBG) log("Registering NetworkAgent"); ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( Context.CONNECTIVITY_SERVICE); - netId = cm.registerNetworkAgent(new Messenger(mHandler), new NetworkInfo(ni), + network = cm.registerNetworkAgent(new Messenger(mHandler), new NetworkInfo(ni), new LinkProperties(lp), new NetworkCapabilities(nc), score, config, providerId); } diff --git a/core/java/android/net/NetworkAgentConfig.java b/core/java/android/net/NetworkAgentConfig.java index 3a383a44cdc3..abc6b67efb11 100644 --- a/core/java/android/net/NetworkAgentConfig.java +++ b/core/java/android/net/NetworkAgentConfig.java @@ -18,22 +18,27 @@ package android.net; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import android.text.TextUtils; /** - * A grab-bag of information (metadata, policies, properties, etc) about a - * {@link Network}. Since this contains PII, it should not be sent outside the - * system. + * Allows a network transport to provide the system with policy and configuration information about + * a particular network when registering a {@link NetworkAgent}. This information cannot change once + * the agent is registered. * * @hide */ -public class NetworkAgentConfig implements Parcelable { +@SystemApi +public final class NetworkAgentConfig implements Parcelable { /** * If the {@link Network} is a VPN, whether apps are allowed to bypass the * VPN. This is set by a {@link VpnService} and used by * {@link ConnectivityManager} when creating a VPN. + * + * @hide */ public boolean allowBypass; @@ -43,6 +48,8 @@ public class NetworkAgentConfig implements Parcelable { * ap in the wifi settings to trigger a connection is explicit. A 3rd party app asking to * connect to a particular access point is also explicit, though this may change in the future * as we want apps to use the multinetwork apis. + * + * @hide */ public boolean explicitlySelected; @@ -50,12 +57,16 @@ public class NetworkAgentConfig implements Parcelable { * Set if the user desires to use this network even if it is unvalidated. This field has meaning * only if {@link explicitlySelected} is true. If it is, this field must also be set to the * appropriate value based on previous user choice. + * + * @hide */ public boolean acceptUnvalidated; /** * Whether the user explicitly set that this network should be validated even if presence of * only partial internet connectivity. + * + * @hide */ public boolean acceptPartialConnectivity; @@ -65,29 +76,62 @@ public class NetworkAgentConfig implements Parcelable { * procedure, a carrier specific provisioning notification will be placed. * only one notification should be displayed. This field is set based on * which notification should be used for provisioning. + * + * @hide */ public boolean provisioningNotificationDisabled; /** + * + * @return whether the sign in to network notification is enabled by this configuration. + */ + public boolean isProvisioningNotificationEnabled() { + return !provisioningNotificationDisabled; + } + + /** * For mobile networks, this is the subscriber ID (such as IMSI). + * + * @hide */ public String subscriberId; /** + * @return the subscriber ID, or null if none. + */ + @Nullable + public String getSubscriberId() { + return subscriberId; + } + + /** * Set to skip 464xlat. This means the device will treat the network as IPv6-only and * will not attempt to detect a NAT64 via RFC 7050 DNS lookups. + * + * @hide */ public boolean skip464xlat; /** + * @return whether NAT64 prefix detection is enabled. + */ + public boolean isNat64DetectionEnabled() { + return !skip464xlat; + } + + /** * Set to true if the PRIVATE_DNS_BROKEN notification has shown for this network. * Reset this bit when private DNS mode is changed from strict mode to opportunistic/off mode. + * + * @hide */ public boolean hasShownBroken; + /** @hide */ public NetworkAgentConfig() { } + /** @hide */ public NetworkAgentConfig(@Nullable NetworkAgentConfig nac) { if (nac != null) { allowBypass = nac.allowBypass; @@ -99,13 +143,63 @@ public class NetworkAgentConfig implements Parcelable { } } + /** + * Builder class to facilitate constructing {@link NetworkAgentConfig} objects. + */ + public static class Builder { + private final NetworkAgentConfig mConfig = new NetworkAgentConfig(); + + /** + * Sets the subscriber ID for this network. + * + * @return this builder, to facilitate chaining. + */ + @NonNull + public Builder setSubscriberId(@Nullable String subscriberId) { + mConfig.subscriberId = subscriberId; + return this; + } + + /** + * Disables active detection of NAT64 (e.g., via RFC 7050 DNS lookups). Used to save power + * and reduce idle traffic on networks that are known to be IPv6-only without a NAT64. + * + * @return this builder, to facilitate chaining. + */ + @NonNull + public Builder disableNat64Detection() { + mConfig.skip464xlat = true; + return this; + } + + /** + * Disables the "Sign in to network" notification. Used if the network transport will + * perform its own carrier-specific provisioning procedure. + * + * @return this builder, to facilitate chaining. + */ + @NonNull + public Builder disableProvisioningNotification() { + mConfig.provisioningNotificationDisabled = true; + return this; + } + + /** + * Returns the constructed {@link NetworkAgentConfig} object. + */ + @NonNull + public NetworkAgentConfig build() { + return mConfig; + } + } + @Override public int describeContents() { return 0; } @Override - public void writeToParcel(Parcel out, int flags) { + public void writeToParcel(@NonNull Parcel out, int flags) { out.writeInt(allowBypass ? 1 : 0); out.writeInt(explicitlySelected ? 1 : 0); out.writeInt(acceptUnvalidated ? 1 : 0); diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java index f6dc52522cb2..428a4ea32b28 100644 --- a/core/java/android/net/NetworkScoreManager.java +++ b/core/java/android/net/NetworkScoreManager.java @@ -163,27 +163,26 @@ public class NetworkScoreManager { public static final String EXTRA_NEW_SCORER = "newScorer"; /** @hide */ - @IntDef({CACHE_FILTER_NONE, CACHE_FILTER_CURRENT_NETWORK, CACHE_FILTER_SCAN_RESULTS}) + @IntDef({SCORE_FILTER_NONE, SCORE_FILTER_CURRENT_NETWORK, SCORE_FILTER_SCAN_RESULTS}) @Retention(RetentionPolicy.SOURCE) - public @interface CacheUpdateFilter {} + public @interface ScoreUpdateFilter {} /** - * Do not filter updates sent to the cache. - * @hide + * Do not filter updates sent to the {@link NetworkScoreCallback}]. */ - public static final int CACHE_FILTER_NONE = 0; + public static final int SCORE_FILTER_NONE = 0; /** - * Only send cache updates when the network matches the connected network. - * @hide + * Only send updates to the {@link NetworkScoreCallback} when the network matches the connected + * network. */ - public static final int CACHE_FILTER_CURRENT_NETWORK = 1; + public static final int SCORE_FILTER_CURRENT_NETWORK = 1; /** - * Only send cache updates when the network is part of the current scan result set. - * @hide + * Only send updates to the {@link NetworkScoreCallback} when the network is part of the + * current scan result set. */ - public static final int CACHE_FILTER_SCAN_RESULTS = 2; + public static final int SCORE_FILTER_SCAN_RESULTS = 2; /** @hide */ @IntDef({RECOMMENDATIONS_ENABLED_FORCED_OFF, RECOMMENDATIONS_ENABLED_OFF, @@ -410,7 +409,7 @@ public class NetworkScoreManager { @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) @Deprecated // migrate to registerNetworkScoreCache(int, INetworkScoreCache, int) public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) { - registerNetworkScoreCache(networkType, scoreCache, CACHE_FILTER_NONE); + registerNetworkScoreCache(networkType, scoreCache, SCORE_FILTER_NONE); } /** @@ -418,7 +417,7 @@ public class NetworkScoreManager { * * @param networkType the type of network this cache can handle. See {@link NetworkKey#type} * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores - * @param filterType the {@link CacheUpdateFilter} to apply + * @param filterType the {@link ScoreUpdateFilter} to apply * @throws SecurityException if the caller does not hold the * {@link permission#REQUEST_NETWORK_SCORES} permission. * @throws IllegalArgumentException if a score cache is already registered for this type. @@ -426,7 +425,7 @@ public class NetworkScoreManager { */ @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache, - @CacheUpdateFilter int filterType) { + @ScoreUpdateFilter int filterType) { try { mService.registerNetworkScoreCache(networkType, scoreCache, filterType); } catch (RemoteException e) { @@ -510,7 +509,7 @@ public class NetworkScoreManager { * Register a network score callback. * * @param networkType the type of network this cache can handle. See {@link NetworkKey#type} - * @param filterType the {@link CacheUpdateFilter} to apply + * @param filterType the {@link ScoreUpdateFilter} to apply * @param callback implementation of {@link NetworkScoreCallback} that will be invoked when the * scores change. * @param executor The executor on which to execute the callbacks. @@ -522,7 +521,7 @@ public class NetworkScoreManager { @SystemApi @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) public void registerNetworkScoreCallback(@NetworkKey.NetworkType int networkType, - @CacheUpdateFilter int filterType, + @ScoreUpdateFilter int filterType, @NonNull @CallbackExecutor Executor executor, @NonNull NetworkScoreCallback callback) throws SecurityException { if (callback == null || executor == null) { diff --git a/core/java/android/os/TimestampedValue.java b/core/java/android/os/TimestampedValue.java index 348574ed43c7..f4c87ac9dfc9 100644 --- a/core/java/android/os/TimestampedValue.java +++ b/core/java/android/os/TimestampedValue.java @@ -18,6 +18,7 @@ package android.os; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import java.util.Objects; @@ -35,19 +36,27 @@ import java.util.Objects; * @param <T> the type of the value with an associated timestamp * @hide */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public final class TimestampedValue<T> implements Parcelable { private final long mReferenceTimeMillis; + @Nullable private final T mValue; - public TimestampedValue(long referenceTimeMillis, T value) { + public TimestampedValue(long referenceTimeMillis, @Nullable T value) { mReferenceTimeMillis = referenceTimeMillis; mValue = value; } + /** Returns the reference time value. See {@link TimestampedValue} for more information. */ public long getReferenceTimeMillis() { return mReferenceTimeMillis; } + /** + * Returns the value associated with the timestamp. See {@link TimestampedValue} for more + * information. + */ + @Nullable public T getValue() { return mValue; } @@ -86,6 +95,8 @@ public final class TimestampedValue<T> implements Parcelable { return one.mReferenceTimeMillis - two.mReferenceTimeMillis; } + /** @hide */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final @NonNull Parcelable.Creator<TimestampedValue<?>> CREATOR = new Parcelable.ClassLoaderCreator<TimestampedValue<?>>() { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 548b1230d6e2..089122ddb023 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -523,7 +523,9 @@ public final class Settings { * Input: The Intent's data URI specifies bootstrapping information for authenticating and * provisioning the peer, and uses a "DPP" scheme. The URI should be attached to the intent * using {@link Intent#setData(Uri)}. The calling app can obtain a DPP URI in any - * way, e.g. by scanning a QR code or other out-of-band methods. + * way, e.g. by scanning a QR code or other out-of-band methods. The calling app may also + * attach the {@link #EXTRA_EASY_CONNECT_BAND_LIST} extra to provide information + * about the bands supported by the enrollee device. * <p> * Output: After calling {@link android.app.Activity#startActivityForResult}, the callback * {@code onActivityResult} will have resultCode {@link android.app.Activity#RESULT_OK} if @@ -595,17 +597,29 @@ public final class Settings { /** * Activity Extra: The Band List that the Enrollee supports. * <p> - * An extra returned on the result intent received when using the {@link - * #ACTION_PROCESS_WIFI_EASY_CONNECT_URI} intent to launch the Easy Connect Operation. This - * extra contains the bands the Enrollee supports, expressed as the Global Operating Class, - * see Table E-4 in IEEE Std 802.11-2016 Global operating classes. This value is populated only - * by remote R2 devices, and only for the following error codes: {@link - * android.net.wifi.EasyConnectStatusCallback#EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK} - * {@link android.net.wifi.EasyConnectStatusCallback#EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION} + * This extra contains the bands the Enrollee supports, expressed as the Global Operating + * Class, see Table E-4 in IEEE Std 802.11-2016 Global operating classes. It is used both as + * input, to configure the Easy Connect operation and as output of the operation. + * <p> + * As input: an optional extra to be attached to the + * {@link #ACTION_PROCESS_WIFI_EASY_CONNECT_URI}. If attached, it indicates the bands which + * the remote device (enrollee, device-to-be-configured) supports. The Settings operation + * may take this into account when presenting the user with list of networks configurations + * to be used. The calling app may obtain this information in any out-of-band method. The + * information should be attached as an array of raw integers - using the + * {@link Intent#putExtra(String, int[])}. + * <p> + * As output: an extra returned on the result intent received when using the + * {@link #ACTION_PROCESS_WIFI_EASY_CONNECT_URI} intent to launch the Easy Connect Operation + * . This value is populated only by remote R2 devices, and only for the following error + * codes: + * {@link android.net.wifi.EasyConnectStatusCallback#EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK}, + * {@link android.net.wifi.EasyConnectStatusCallback#EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION}, + * or * {@link android.net.wifi.EasyConnectStatusCallback#EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION}. - * Therefore, always check if this extra is available using {@link Intent#hasExtra(String)}. If - * there is no error, i.e. if the operation returns {@link android.app.Activity#RESULT_OK}, then - * this extra is not attached to the result intent. + * Therefore, always check if this extra is available using {@link Intent#hasExtra(String)}. + * If there is no error, i.e. if the operation returns {@link android.app.Activity#RESULT_OK} + * , then this extra is not attached to the result intent. * <p> * Use the {@link Intent#getIntArrayExtra(String)} to obtain the list. */ diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index 1b2db36c1335..9d22d304ad00 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -42,6 +42,8 @@ public class FeatureFlagUtils { public static final String DYNAMIC_SYSTEM = "settings_dynamic_system"; public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2"; public static final String SETTINGS_FUSE_FLAG = "settings_fuse"; + public static final String NOTIF_CONVO_BYPASS_SHORTCUT_REQ = + "settings_notif_convo_bypass_shortcut_req"; private static final Map<String, String> DEFAULT_FLAGS; @@ -60,6 +62,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put("settings_work_profile", "true"); DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "false"); DEFAULT_FLAGS.put("settings_conditionals", "false"); + DEFAULT_FLAGS.put(NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false"); } /** diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index ca8ba4ca1b8a..e0f6e0668f8b 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -826,6 +826,10 @@ public final class ViewRootImpl implements ViewParent, if (mWindowAttributes.packageName == null) { mWindowAttributes.packageName = mBasePackageName; } + if (WindowManagerGlobal.USE_BLAST_ADAPTER) { + mWindowAttributes.privateFlags |= + WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST; + } attrs = mWindowAttributes; setTag(); @@ -1308,7 +1312,7 @@ public final class ViewRootImpl implements ViewParent, mWindowAttributes.privateFlags |= compatibleWindowFlag; if (WindowManagerGlobal.USE_BLAST_ADAPTER) { - mWindowAttributes.privateFlags = + mWindowAttributes.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST; } diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java index 386c9cb9d14f..860ce90d5fc0 100644 --- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java +++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java @@ -17,6 +17,8 @@ package android.view.inputmethod; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ActivityThread; import android.os.Parcelable; import android.view.inline.InlinePresentationSpec; @@ -49,6 +51,21 @@ public final class InlineSuggestionsRequest implements Parcelable { */ private final @NonNull List<InlinePresentationSpec> mPresentationSpecs; + /** + * The package name of the app that requests for the inline suggestions and will host the + * embedded suggestion views. The app does not have to set the value for the field because + * it'll be set by the system for safety reasons. + */ + private @NonNull String mHostPackageName; + + /** + * @hide + * @see {@link #mHostPackageName}. + */ + public void setHostPackageName(@NonNull String hostPackageName) { + mHostPackageName = hostPackageName; + } + private void onConstructed() { Preconditions.checkState(mMaxSuggestionCount >= mPresentationSpecs.size()); } @@ -57,9 +74,15 @@ public final class InlineSuggestionsRequest implements Parcelable { return SUGGESTION_COUNT_UNLIMITED; } + private static String defaultHostPackageName() { + return ActivityThread.currentPackageName(); + } + /** @hide */ abstract static class BaseBuilder { abstract Builder setPresentationSpecs(@NonNull List<InlinePresentationSpec> value); + + abstract Builder setHostPackageName(@Nullable String value); } @@ -80,11 +103,15 @@ public final class InlineSuggestionsRequest implements Parcelable { @DataClass.Generated.Member /* package-private */ InlineSuggestionsRequest( int maxSuggestionCount, - @NonNull List<InlinePresentationSpec> presentationSpecs) { + @NonNull List<InlinePresentationSpec> presentationSpecs, + @NonNull String hostPackageName) { this.mMaxSuggestionCount = maxSuggestionCount; this.mPresentationSpecs = presentationSpecs; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mPresentationSpecs); + this.mHostPackageName = hostPackageName; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mHostPackageName); onConstructed(); } @@ -108,6 +135,16 @@ public final class InlineSuggestionsRequest implements Parcelable { return mPresentationSpecs; } + /** + * The package name of the app that requests for the inline suggestions and will host the + * embedded suggestion views. The app does not have to set the value for the field because + * it'll be set by the system for safety reasons. + */ + @DataClass.Generated.Member + public @NonNull String getHostPackageName() { + return mHostPackageName; + } + @Override @DataClass.Generated.Member public String toString() { @@ -116,13 +153,14 @@ public final class InlineSuggestionsRequest implements Parcelable { return "InlineSuggestionsRequest { " + "maxSuggestionCount = " + mMaxSuggestionCount + ", " + - "presentationSpecs = " + mPresentationSpecs + + "presentationSpecs = " + mPresentationSpecs + ", " + + "hostPackageName = " + mHostPackageName + " }"; } @Override @DataClass.Generated.Member - public boolean equals(@android.annotation.Nullable Object o) { + public boolean equals(@Nullable Object o) { // You can override field equality logic by defining either of the methods like: // boolean fieldNameEquals(InlineSuggestionsRequest other) { ... } // boolean fieldNameEquals(FieldType otherValue) { ... } @@ -134,7 +172,8 @@ public final class InlineSuggestionsRequest implements Parcelable { //noinspection PointlessBooleanExpression return true && mMaxSuggestionCount == that.mMaxSuggestionCount - && java.util.Objects.equals(mPresentationSpecs, that.mPresentationSpecs); + && java.util.Objects.equals(mPresentationSpecs, that.mPresentationSpecs) + && java.util.Objects.equals(mHostPackageName, that.mHostPackageName); } @Override @@ -146,6 +185,7 @@ public final class InlineSuggestionsRequest implements Parcelable { int _hash = 1; _hash = 31 * _hash + mMaxSuggestionCount; _hash = 31 * _hash + java.util.Objects.hashCode(mPresentationSpecs); + _hash = 31 * _hash + java.util.Objects.hashCode(mHostPackageName); return _hash; } @@ -157,6 +197,7 @@ public final class InlineSuggestionsRequest implements Parcelable { dest.writeInt(mMaxSuggestionCount); dest.writeParcelableList(mPresentationSpecs, flags); + dest.writeString(mHostPackageName); } @Override @@ -173,11 +214,15 @@ public final class InlineSuggestionsRequest implements Parcelable { int maxSuggestionCount = in.readInt(); List<InlinePresentationSpec> presentationSpecs = new ArrayList<>(); in.readParcelableList(presentationSpecs, InlinePresentationSpec.class.getClassLoader()); + String hostPackageName = in.readString(); this.mMaxSuggestionCount = maxSuggestionCount; this.mPresentationSpecs = presentationSpecs; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mPresentationSpecs); + this.mHostPackageName = hostPackageName; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mHostPackageName); onConstructed(); } @@ -205,6 +250,7 @@ public final class InlineSuggestionsRequest implements Parcelable { private int mMaxSuggestionCount; private @NonNull List<InlinePresentationSpec> mPresentationSpecs; + private @NonNull String mHostPackageName; private long mBuilderFieldsSet = 0L; @@ -260,22 +306,40 @@ public final class InlineSuggestionsRequest implements Parcelable { return this; } + /** + * The package name of the app that requests for the inline suggestions and will host the + * embedded suggestion views. The app does not have to set the value for the field because + * it'll be set by the system for safety reasons. + */ + @DataClass.Generated.Member + @Override + @NonNull Builder setHostPackageName(@NonNull String value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x4; + mHostPackageName = value; + return this; + } + /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull InlineSuggestionsRequest build() { checkNotUsed(); - mBuilderFieldsSet |= 0x4; // Mark builder used + mBuilderFieldsSet |= 0x8; // Mark builder used if ((mBuilderFieldsSet & 0x1) == 0) { mMaxSuggestionCount = defaultMaxSuggestionCount(); } + if ((mBuilderFieldsSet & 0x4) == 0) { + mHostPackageName = defaultHostPackageName(); + } InlineSuggestionsRequest o = new InlineSuggestionsRequest( mMaxSuggestionCount, - mPresentationSpecs); + mPresentationSpecs, + mHostPackageName); return o; } private void checkNotUsed() { - if ((mBuilderFieldsSet & 0x4) != 0) { + if ((mBuilderFieldsSet & 0x8) != 0) { throw new IllegalStateException( "This Builder should not be reused. Use a new Builder instance instead"); } @@ -283,10 +347,10 @@ public final class InlineSuggestionsRequest implements Parcelable { } @DataClass.Generated( - time = 1576637222199L, + time = 1578948035951L, codegenVersion = "1.0.14", sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java", - inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.view.inline.InlinePresentationSpec> mPresentationSpecs\nprivate void onConstructed()\nprivate static int defaultMaxSuggestionCount()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setPresentationSpecs(java.util.List<android.view.inline.InlinePresentationSpec>)\nclass BaseBuilder extends java.lang.Object implements []") + inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.view.inline.InlinePresentationSpec> mPresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\npublic void setHostPackageName(java.lang.String)\nprivate void onConstructed()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setPresentationSpecs(java.util.List<android.view.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nclass BaseBuilder extends java.lang.Object implements []") @Deprecated private void __metadata() {} diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 20af76b0d5ca..f851e10fa4f6 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -5737,7 +5737,7 @@ public class Editor { private boolean mIsDraggingCursor; public void onTouchEvent(MotionEvent event) { - if (getSelectionController().isCursorBeingModified()) { + if (hasSelectionController() && getSelectionController().isCursorBeingModified()) { return; } switch (event.getActionMasked()) { diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 6e6746f16748..a2f514a85ff8 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -344,7 +344,6 @@ cc_library_static { cppflags: ["-Wno-conversion-null"], srcs: [ - "android/graphics/apex/android_bitmap.cpp", "android/graphics/apex/android_matrix.cpp", "android/graphics/apex/android_paint.cpp", "android/graphics/apex/android_region.cpp", @@ -430,6 +429,7 @@ cc_library_static { android: { srcs: [ // sources that depend on android only libraries "android/graphics/apex/android_canvas.cpp", + "android/graphics/apex/android_bitmap.cpp", "android/graphics/apex/renderthread.cpp", "android/graphics/apex/jni_runtime.cpp", diff --git a/core/jni/android/graphics/apex/android_bitmap.cpp b/core/jni/android/graphics/apex/android_bitmap.cpp index 90cc98699827..6a3c01efe98c 100644 --- a/core/jni/android/graphics/apex/android_bitmap.cpp +++ b/core/jni/android/graphics/apex/android_bitmap.cpp @@ -122,6 +122,98 @@ AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmapHandle) { return getInfo(bitmap->info(), bitmap->rowBytes()); } +static bool nearlyEqual(float a, float b) { + // By trial and error, this is close enough to match for the ADataSpaces we + // compare for. + return ::fabs(a - b) < .002f; +} + +static bool nearlyEqual(const skcms_TransferFunction& x, const skcms_TransferFunction& y) { + return nearlyEqual(x.g, y.g) + && nearlyEqual(x.a, y.a) + && nearlyEqual(x.b, y.b) + && nearlyEqual(x.c, y.c) + && nearlyEqual(x.d, y.d) + && nearlyEqual(x.e, y.e) + && nearlyEqual(x.f, y.f); +} + +static bool nearlyEqual(const skcms_Matrix3x3& x, const skcms_Matrix3x3& y) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (!nearlyEqual(x.vals[i][j], y.vals[i][j])) return false; + } + } + return true; +} + +static constexpr skcms_TransferFunction k2Dot6 = {2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; + +// Skia's SkNamedGamut::kDCIP3 is based on a white point of D65. This gamut +// matches the white point used by ColorSpace.Named.DCIP3. +static constexpr skcms_Matrix3x3 kDCIP3 = {{ + {0.486143, 0.323835, 0.154234}, + {0.226676, 0.710327, 0.0629966}, + {0.000800549, 0.0432385, 0.78275}, +}}; + +ADataSpace ABitmap_getDataSpace(ABitmap* bitmapHandle) { + Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle); + const SkImageInfo& info = bitmap->info(); + SkColorSpace* colorSpace = info.colorSpace(); + if (!colorSpace) { + return ADATASPACE_UNKNOWN; + } + + if (colorSpace->isSRGB()) { + if (info.colorType() == kRGBA_F16_SkColorType) { + return ADATASPACE_SCRGB; + } + return ADATASPACE_SRGB; + } + + skcms_TransferFunction fn; + LOG_ALWAYS_FATAL_IF(!colorSpace->isNumericalTransferFn(&fn)); + + skcms_Matrix3x3 gamut; + LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&gamut)); + + if (nearlyEqual(gamut, SkNamedGamut::kSRGB)) { + if (nearlyEqual(fn, SkNamedTransferFn::kLinear)) { + // Skia doesn't differentiate amongst the RANGES. In Java, we associate + // LINEAR_EXTENDED_SRGB with F16, and LINEAR_SRGB with other Configs. + // Make the same association here. + if (info.colorType() == kRGBA_F16_SkColorType) { + return ADATASPACE_SCRGB_LINEAR; + } + return ADATASPACE_SRGB_LINEAR; + } + + if (nearlyEqual(fn, SkNamedTransferFn::kRec2020)) { + return ADATASPACE_BT709; + } + } + + if (nearlyEqual(fn, SkNamedTransferFn::kSRGB) && nearlyEqual(gamut, SkNamedGamut::kDCIP3)) { + return ADATASPACE_DISPLAY_P3; + } + + if (nearlyEqual(fn, SkNamedTransferFn::k2Dot2) && nearlyEqual(gamut, SkNamedGamut::kAdobeRGB)) { + return ADATASPACE_ADOBE_RGB; + } + + if (nearlyEqual(fn, SkNamedTransferFn::kRec2020) && + nearlyEqual(gamut, SkNamedGamut::kRec2020)) { + return ADATASPACE_BT2020; + } + + if (nearlyEqual(fn, k2Dot6) && nearlyEqual(gamut, kDCIP3)) { + return ADATASPACE_DCI_P3; + } + + return ADATASPACE_UNKNOWN; +} + AndroidBitmapInfo ABitmap_getInfoFromJava(JNIEnv* env, jobject bitmapObj) { uint32_t rowBytes = 0; SkImageInfo imageInfo = GraphicsJNI::getBitmapInfo(env, bitmapObj, &rowBytes); diff --git a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h index f231eeddb7e2..32b8a450e147 100644 --- a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h +++ b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h @@ -17,6 +17,7 @@ #define ANDROID_GRAPHICS_BITMAP_H #include <android/bitmap.h> +#include <android/data_space.h> #include <jni.h> #include <sys/cdefs.h> @@ -49,6 +50,7 @@ void ABitmap_acquireRef(ABitmap* bitmap); void ABitmap_releaseRef(ABitmap* bitmap); AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmap); +ADataSpace ABitmap_getDataSpace(ABitmap* bitmap); void* ABitmap_getPixels(ABitmap* bitmap); void ABitmap_notifyPixelsChanged(ABitmap* bitmap); @@ -106,6 +108,7 @@ namespace graphics { ABitmap* get() const { return mBitmap; } AndroidBitmapInfo getInfo() const { return ABitmap_getInfo(mBitmap); } + ADataSpace getDataSpace() const { return ABitmap_getDataSpace(mBitmap); } void* getPixels() const { return ABitmap_getPixels(mBitmap); } void notifyPixelsChanged() const { ABitmap_notifyPixelsChanged(mBitmap); } @@ -119,4 +122,4 @@ namespace graphics { }; // namespace android #endif // __cplusplus -#endif // ANDROID_GRAPHICS_BITMAP_H
\ No newline at end of file +#endif // ANDROID_GRAPHICS_BITMAP_H diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 466544c1448e..673772a52212 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -1156,6 +1156,36 @@ static void isolateAppDataPerPackage(int userId, std::string_view package_name, createAndMountAppData(package_name, ce_data_path, mirrorCePath, actualCePath, fail_fn); } +// Relabel directory +static void relabelDir(const char* path, security_context_t context, fail_fn_t fail_fn) { + if (setfilecon(path, context) != 0) { + fail_fn(CREATE_ERROR("Failed to setfilecon %s %s", path, strerror(errno))); + } +} + +// Relabel all directories under a path non-recursively. +static void relabelAllDirs(const char* path, security_context_t context, fail_fn_t fail_fn) { + DIR* dir = opendir(path); + if (dir == nullptr) { + fail_fn(CREATE_ERROR("Failed to opendir %s", path)); + } + struct dirent* ent; + while ((ent = readdir(dir))) { + if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue; + auto filePath = StringPrintf("%s/%s", path, ent->d_name); + if (ent->d_type == DT_DIR) { + relabelDir(filePath.c_str(), context, fail_fn); + } else if (ent->d_type == DT_LNK) { + if (lsetfilecon(filePath.c_str(), context) != 0) { + fail_fn(CREATE_ERROR("Failed to lsetfilecon %s %s", filePath.c_str(), strerror(errno))); + } + } else { + fail_fn(CREATE_ERROR("Unexpected type: %d %s", ent->d_type, filePath.c_str())); + } + } + closedir(dir); +} + /** * Make other apps data directory not visible in CE, DE storage. * @@ -1215,10 +1245,36 @@ static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list, snprintf(internalDePath, PATH_MAX, "/data/user_de"); snprintf(externalPrivateMountPath, PATH_MAX, "/mnt/expand"); + security_context_t dataDataContext = nullptr; + if (getfilecon(internalDePath, &dataDataContext) < 0) { + fail_fn(CREATE_ERROR("Unable to getfilecon on %s %s", internalDePath, + strerror(errno))); + } + MountAppDataTmpFs(internalLegacyCePath, fail_fn); MountAppDataTmpFs(internalCePath, fail_fn); MountAppDataTmpFs(internalDePath, fail_fn); - MountAppDataTmpFs(externalPrivateMountPath, fail_fn); + + // Mount tmpfs on all external vols DE and CE storage + DIR* dir = opendir(externalPrivateMountPath); + if (dir == nullptr) { + fail_fn(CREATE_ERROR("Failed to opendir %s", externalPrivateMountPath)); + } + struct dirent* ent; + while ((ent = readdir(dir))) { + if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue; + if (ent->d_type != DT_DIR) { + fail_fn(CREATE_ERROR("Unexpected type: %d %s", ent->d_type, ent->d_name)); + } + auto volPath = StringPrintf("%s/%s", externalPrivateMountPath, ent->d_name); + auto cePath = StringPrintf("%s/user", volPath.c_str()); + auto dePath = StringPrintf("%s/user_de", volPath.c_str()); + MountAppDataTmpFs(cePath.c_str(), fail_fn); + MountAppDataTmpFs(dePath.c_str(), fail_fn); + } + closedir(dir); + + bool legacySymlinkCreated = false; for (int i = 0; i < size; i += 3) { jstring package_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i)); @@ -1266,7 +1322,14 @@ static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list, // If it's user 0, create a symlink /data/user/0 -> /data/data, // otherwise create /data/user/$USER if (userId == 0) { - symlink(internalLegacyCePath, internalCeUserPath); + if (!legacySymlinkCreated) { + legacySymlinkCreated = true; + int result = symlink(internalLegacyCePath, internalCeUserPath); + if (result != 0) { + fail_fn(CREATE_ERROR("Failed to create symlink %s %s", internalCeUserPath, + strerror(errno))); + } + } actualCePath = internalLegacyCePath; } else { PrepareDirIfNotPresent(internalCeUserPath, DEFAULT_DATA_DIR_PERMISSION, @@ -1280,6 +1343,43 @@ static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list, isolateAppDataPerPackage(userId, packageName, volUuid, ceDataInode, actualCePath, actualDePath, fail_fn); } + // We set the label AFTER everything is done, as we are applying + // the file operations on tmpfs. If we set the label when we mount + // tmpfs, SELinux will not happy as we are changing system_data_files. + // Relabel dir under /data/user, including /data/user/0 + relabelAllDirs(internalCePath, dataDataContext, fail_fn); + + // Relabel /data/user + relabelDir(internalCePath, dataDataContext, fail_fn); + + // Relabel /data/data + relabelDir(internalLegacyCePath, dataDataContext, fail_fn); + + // Relabel dir under /data/user_de + relabelAllDirs(internalDePath, dataDataContext, fail_fn); + + // Relabel /data/user_de + relabelDir(internalDePath, dataDataContext, fail_fn); + + // Relabel CE and DE dirs under /mnt/expand + dir = opendir(externalPrivateMountPath); + if (dir == nullptr) { + fail_fn(CREATE_ERROR("Failed to opendir %s", externalPrivateMountPath)); + } + while ((ent = readdir(dir))) { + if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue; + auto volPath = StringPrintf("%s/%s", externalPrivateMountPath, ent->d_name); + auto cePath = StringPrintf("%s/user", volPath.c_str()); + auto dePath = StringPrintf("%s/user_de", volPath.c_str()); + + relabelAllDirs(cePath.c_str(), dataDataContext, fail_fn); + relabelDir(cePath.c_str(), dataDataContext, fail_fn); + relabelAllDirs(dePath.c_str(), dataDataContext, fail_fn); + relabelDir(dePath.c_str(), dataDataContext, fail_fn); + } + closedir(dir); + + freecon(dataDataContext); } // Utility routine to specialize a zygote child process. diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index b78b18192f45..7ecd9b702e53 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2568,7 +2568,7 @@ <!-- Allows telephony to suggest the time / time zone. <p>Not for use by third-party applications. - @hide + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @hide --> <permission android:name="android.permission.SUGGEST_PHONE_TIME_AND_ZONE" android:protectionLevel="signature|telephony" /> diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java index 89c237498e5c..8c9b4d071c2d 100644 --- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java +++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java @@ -67,6 +67,7 @@ public class EditorCursorDragTest { mOriginalFlagValue = Editor.FLAG_ENABLE_CURSOR_DRAG; Editor.FLAG_ENABLE_CURSOR_DRAG = true; } + @After public void after() throws Throwable { Editor.FLAG_ENABLE_CURSOR_DRAG = mOriginalFlagValue; @@ -356,6 +357,23 @@ public class EditorCursorDragTest { assertFalse(editor.getSelectionController().isCursorBeingModified()); } + @Test // Reproduces b/147366705 + public void testCursorDrag_nonSelectableTextView() throws Throwable { + String text = "Hello world!"; + TextView tv = mActivity.findViewById(R.id.nonselectable_textview); + tv.setText(text); + Editor editor = tv.getEditorForTesting(); + + // Simulate a tap. No error should be thrown. + long event1Time = 1001; + MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f); + mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1)); + + // Swipe left to right. No error should be thrown. + onView(withId(R.id.nonselectable_textview)).perform( + dragOnText(text.indexOf("llo"), text.indexOf("!"))); + } + private static MotionEvent downEvent(long downTime, long eventTime, float x, float y) { return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0); } diff --git a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java index b4116681e723..aa55e08dbcdc 100644 --- a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java +++ b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java @@ -19,7 +19,6 @@ package android.widget; import static android.widget.espresso.ContextMenuUtils.assertContextMenuContainsItemDisabled; import static android.widget.espresso.ContextMenuUtils.assertContextMenuContainsItemEnabled; import static android.widget.espresso.ContextMenuUtils.assertContextMenuIsNotDisplayed; -import static android.widget.espresso.DragHandleUtils.assertNoSelectionHandles; import static android.widget.espresso.DragHandleUtils.onHandleView; import static android.widget.espresso.TextViewActions.mouseClick; import static android.widget.espresso.TextViewActions.mouseClickOnTextAtIndex; @@ -64,7 +63,6 @@ import org.junit.runner.RunWith; */ @RunWith(AndroidJUnit4.class) @MediumTest -@Suppress // Consistently failing. b/29591177 public class TextViewActivityMouseTest { @Rule @@ -86,11 +84,8 @@ public class TextViewActivityMouseTest { onView(withId(R.id.textview)).perform(mouseClick()); onView(withId(R.id.textview)).perform(replaceText(helloWorld)); - assertNoSelectionHandles(); - onView(withId(R.id.textview)).perform( mouseDragOnText(helloWorld.indexOf("llo"), helloWorld.indexOf("ld!"))); - onView(withId(R.id.textview)).check(hasSelection("llo wor")); onHandleView(com.android.internal.R.id.selection_start_handle) @@ -100,8 +95,6 @@ public class TextViewActivityMouseTest { onView(withId(R.id.textview)).perform(mouseClickOnTextAtIndex(helloWorld.indexOf("w"))); onView(withId(R.id.textview)).check(hasSelection("")); - - assertNoSelectionHandles(); } @Test @@ -196,11 +189,11 @@ public class TextViewActivityMouseTest { onView(withId(R.id.textview)).check(matches(withText("abc ghi.def"))); onView(withId(R.id.textview)).check(hasSelection("")); - assertNoSelectionHandles(); onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex("abc ghi.def".length())); } @Test + @Suppress // Consistently failing. b/29591177 public void testDragAndDrop_longClick() { final String text = "abc def ghi."; onView(withId(R.id.textview)).perform(mouseClick()); @@ -213,7 +206,6 @@ public class TextViewActivityMouseTest { onView(withId(R.id.textview)).check(matches(withText("abc ghi.def"))); onView(withId(R.id.textview)).check(hasSelection("")); - assertNoSelectionHandles(); onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex("abc ghi.def".length())); } diff --git a/core/tests/coretests/src/android/widget/espresso/MouseUiController.java b/core/tests/coretests/src/android/widget/espresso/MouseUiController.java index abee7369414b..1928d2587f70 100644 --- a/core/tests/coretests/src/android/widget/espresso/MouseUiController.java +++ b/core/tests/coretests/src/android/widget/espresso/MouseUiController.java @@ -70,6 +70,8 @@ public final class MouseUiController implements UiController { event.setSource(InputDevice.SOURCE_MOUSE); if (event.getActionMasked() != MotionEvent.ACTION_UP) { event.setButtonState(mButton); + } else { + event.setButtonState(0); } return mUiController.injectMotionEvent(event); } diff --git a/media/java/android/media/IMediaRoute2ProviderClient.aidl b/media/java/android/media/IMediaRoute2ProviderClient.aidl index e8abfdca89b7..0fccb3a9aeac 100644 --- a/media/java/android/media/IMediaRoute2ProviderClient.aidl +++ b/media/java/android/media/IMediaRoute2ProviderClient.aidl @@ -25,8 +25,10 @@ import android.os.Bundle; * @hide */ oneway interface IMediaRoute2ProviderClient { - void updateState(in MediaRoute2ProviderInfo providerInfo, - in List<RoutingSessionInfo> sessionInfos); - void notifySessionCreated(in @nullable RoutingSessionInfo sessionInfo, long requestId); - void notifySessionInfoChanged(in RoutingSessionInfo sessionInfo); + // TODO: Change it to updateRoutes? + void updateState(in MediaRoute2ProviderInfo providerInfo); + void notifySessionCreated(in RoutingSessionInfo sessionInfo, long requestId); + void notifySessionCreationFailed(long requestId); + void notifySessionUpdated(in RoutingSessionInfo sessionInfo); + void notifySessionReleased(in RoutingSessionInfo sessionInfo); } diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java index 1cd5dfa087fa..6d9aea512f01 100644 --- a/media/java/android/media/MediaRoute2ProviderService.java +++ b/media/java/android/media/MediaRoute2ProviderService.java @@ -58,6 +58,16 @@ public abstract class MediaRoute2ProviderService extends Service { public static final String SERVICE_INTERFACE = "android.media.MediaRoute2ProviderService"; + /** + * The request ID to pass {@link #notifySessionCreated(RoutingSessionInfo, long)} + * when {@link MediaRoute2ProviderService} created a session although there was no creation + * request. + * + * @see #notifySessionCreated(RoutingSessionInfo, long) + * @hide + */ + public static final long REQUEST_ID_UNKNOWN = 0; + private final Handler mHandler; private final Object mSessionLock = new Object(); private final AtomicBoolean mStatePublishScheduled = new AtomicBoolean(false); @@ -118,7 +128,7 @@ public abstract class MediaRoute2ProviderService extends Service { * * @param sessionId id of the session * @return information of the session with the given id. - * null if the session is destroyed or id is not valid. + * null if the session is released or ID is not valid. * @hide */ @Nullable @@ -143,161 +153,178 @@ public abstract class MediaRoute2ProviderService extends Service { } /** - * Updates the information of a session. - * If the session is destroyed or not created before, it will be ignored. - * Call {@link #updateProviderInfo(MediaRoute2ProviderInfo)} to notify clients of - * session info changes. + * Notifies clients of that the session is created and ready for use. + * <p> + * If this session is created without any creation request, use {@link #REQUEST_ID_UNKNOWN} + * as the request ID. * - * @param sessionInfo new session information - * @see #notifySessionCreated(RoutingSessionInfo, long) + * @param sessionInfo information of the new session. + * The {@link RoutingSessionInfo#getId() id} of the session must be unique. + * @param requestId id of the previous request to create this session provided in + * {@link #onCreateSession(String, String, String, long)} + * @see #onCreateSession(String, String, String, long) * @hide */ - public final void updateSessionInfo(@NonNull RoutingSessionInfo sessionInfo) { + public final void notifySessionCreated(@NonNull RoutingSessionInfo sessionInfo, + long requestId) { Objects.requireNonNull(sessionInfo, "sessionInfo must not be null"); - String sessionId = sessionInfo.getId(); + String sessionId = sessionInfo.getId(); synchronized (mSessionLock) { if (mSessionInfo.containsKey(sessionId)) { - mSessionInfo.put(sessionId, sessionInfo); - schedulePublishState(); - } else { - Log.w(TAG, "Ignoring unknown session info."); + Log.w(TAG, "Ignoring duplicate session id."); return; } + mSessionInfo.put(sessionInfo.getId(), sessionInfo); + } + schedulePublishState(); + + if (mClient == null) { + return; + } + try { + // TODO: Calling binder calls in multiple thread may cause timing issue. + // Consider to change implementations to avoid the problems. + // For example, post binder calls, always send all sessions at once, etc. + mClient.notifySessionCreated(sessionInfo, requestId); + } catch (RemoteException ex) { + Log.w(TAG, "Failed to notify session created."); } } /** - * Notifies the session is changed. + * Notifies clients of that the session could not be created. * - * TODO: This method is temporary, only created for tests. Remove when the alternative is ready. + * @param requestId id of the previous request to create the session provided in + * {@link #onCreateSession(String, String, String, long)}. + * @see #onCreateSession(String, String, String, long) * @hide */ - public final void notifySessionInfoChanged(@NonNull RoutingSessionInfo sessionInfo) { - Objects.requireNonNull(sessionInfo, "sessionInfo must not be null"); - - String sessionId = sessionInfo.getId(); - synchronized (mSessionLock) { - if (mSessionInfo.containsKey(sessionId)) { - mSessionInfo.put(sessionId, sessionInfo); - } else { - Log.w(TAG, "Ignoring unknown session info."); - return; - } - } - + public final void notifySessionCreationFailed(long requestId) { if (mClient == null) { return; } try { - mClient.notifySessionInfoChanged(sessionInfo); + mClient.notifySessionCreationFailed(requestId); } catch (RemoteException ex) { - Log.w(TAG, "Failed to notify session info changed."); + Log.w(TAG, "Failed to notify session creation failed."); } } /** - * Notifies clients of that the session is created and ready for use. If the session can be - * controlled, pass a {@link Bundle} that contains how to control it. + * Notifies the existing session is updated. For example, when + * {@link RoutingSessionInfo#getSelectedRoutes() selected routes} are changed. * - * @param sessionInfo information of the new session. - * The {@link RoutingSessionInfo#getId() id} of the session must be - * unique. Pass {@code null} to reject the request or inform clients that - * session creation is failed. - * @param requestId id of the previous request to create this session * @hide */ - // TODO: fail reason? - // TODO: Maybe better to create notifySessionCreationFailed? - public final void notifySessionCreated(@Nullable RoutingSessionInfo sessionInfo, - long requestId) { - if (sessionInfo != null) { - String sessionId = sessionInfo.getId(); - synchronized (mSessionLock) { - if (mSessionInfo.containsKey(sessionId)) { - Log.w(TAG, "Ignoring duplicate session id."); - return; - } - mSessionInfo.put(sessionInfo.getId(), sessionInfo); + public final void notifySessionUpdated(@NonNull RoutingSessionInfo sessionInfo) { + Objects.requireNonNull(sessionInfo, "sessionInfo must not be null"); + + String sessionId = sessionInfo.getId(); + synchronized (mSessionLock) { + if (mSessionInfo.containsKey(sessionId)) { + mSessionInfo.put(sessionId, sessionInfo); + } else { + Log.w(TAG, "Ignoring unknown session info."); + return; } - schedulePublishState(); } if (mClient == null) { return; } try { - mClient.notifySessionCreated(sessionInfo, requestId); + mClient.notifySessionUpdated(sessionInfo); } catch (RemoteException ex) { - Log.w(TAG, "Failed to notify session created."); + Log.w(TAG, "Failed to notify session info changed."); } } /** - * Releases a session with the given id. - * {@link #onDestroySession} is called if the session is released. + * Notifies that the session is released. * - * @param sessionId id of the session to be released - * @see #onDestroySession(String, RoutingSessionInfo) + * @param sessionId id of the released session. + * @see #onReleaseSession(String) * @hide */ - public final void releaseSession(@NonNull String sessionId) { + public final void notifySessionReleased(@NonNull String sessionId) { if (TextUtils.isEmpty(sessionId)) { throw new IllegalArgumentException("sessionId must not be empty"); } - //TODO: notify media router service of release. RoutingSessionInfo sessionInfo; synchronized (mSessionLock) { sessionInfo = mSessionInfo.remove(sessionId); } - if (sessionInfo != null) { - mHandler.sendMessage(obtainMessage( - MediaRoute2ProviderService::onDestroySession, this, sessionId, sessionInfo)); - schedulePublishState(); + + if (sessionInfo == null) { + Log.w(TAG, "Ignoring unknown session info."); + return; + } + + if (mClient == null) { + return; + } + try { + mClient.notifySessionReleased(sessionInfo); + } catch (RemoteException ex) { + Log.w(TAG, "Failed to notify session info changed."); } } /** - * Called when a session should be created. + * Called when the service receives a request to create a session. + * <p> * You should create and maintain your own session and notifies the client of * session info. Call {@link #notifySessionCreated(RoutingSessionInfo, long)} * with the given {@code requestId} to notify the information of a new session. - * If you can't create the session or want to reject the request, pass {@code null} - * as session info in {@link #notifySessionCreated(RoutingSessionInfo, long)} - * with the given {@code requestId}. + * The created session must have the same route feature and must include the given route + * specified by {@code routeId}. + * <p> + * If the session can be controlled, you can optionally pass the control hints to + * {@link RoutingSessionInfo.Builder#setControlHints(Bundle)}. Control hints is a + * {@link Bundle} which contains how to control the session. + * <p> + * If you can't create the session or want to reject the request, call + * {@link #notifySessionCreationFailed(long)} with the given {@code requestId}. * * @param packageName the package name of the application that selected the route * @param routeId the id of the route initially being connected * @param routeFeature the route feature of the new session * @param requestId the id of this session creation request + * + * @see RoutingSessionInfo.Builder#Builder(String, String, String) + * @see RoutingSessionInfo.Builder#addSelectedRoute(String) + * @see RoutingSessionInfo.Builder#setControlHints(Bundle) * @hide */ public abstract void onCreateSession(@NonNull String packageName, @NonNull String routeId, @NonNull String routeFeature, long requestId); /** - * Called when a session is about to be destroyed. - * You can clean up your session here. This can happen by the - * client or provider itself. + * Called when the session should be released. A client of the session or system can request + * a session to be released. + * <p> + * After releasing the session, call {@link #notifySessionReleased(String)} + * with the ID of the released session. + * + * Note: Calling {@link #notifySessionReleased(String)} will <em>NOT</em> trigger + * this method to be called. * - * @param sessionId id of the session being destroyed. - * @param lastSessionInfo information of the session being destroyed. - * @see #releaseSession(String) + * @param sessionId id of the session being released. + * @see #notifySessionReleased(String) + * @see #getSessionInfo(String) * @hide */ - public abstract void onDestroySession(@NonNull String sessionId, - @NonNull RoutingSessionInfo lastSessionInfo); + public abstract void onReleaseSession(@NonNull String sessionId); //TODO: make a way to reject the request /** * Called when a client requests selecting a route for the session. - * After the route is selected, call {@link #updateSessionInfo(RoutingSessionInfo)} to update - * session info and call {@link #updateProviderInfo(MediaRoute2ProviderInfo)} to notify - * clients of updated session info. + * After the route is selected, call {@link #notifySessionUpdated(RoutingSessionInfo)} + * to update session info. * * @param sessionId id of the session * @param routeId id of the route - * @see #updateSessionInfo(RoutingSessionInfo) * @hide */ public abstract void onSelectRoute(@NonNull String sessionId, @NonNull String routeId); @@ -305,9 +332,8 @@ public abstract class MediaRoute2ProviderService extends Service { //TODO: make a way to reject the request /** * Called when a client requests deselecting a route from the session. - * After the route is deselected, call {@link #updateSessionInfo(RoutingSessionInfo)} to update - * session info and call {@link #updateProviderInfo(MediaRoute2ProviderInfo)} to notify - * clients of updated session info. + * After the route is deselected, call {@link #notifySessionUpdated(RoutingSessionInfo)} + * to update session info. * * @param sessionId id of the session * @param routeId id of the route @@ -318,9 +344,8 @@ public abstract class MediaRoute2ProviderService extends Service { //TODO: make a way to reject the request /** * Called when a client requests transferring a session to a route. - * After the transfer is finished, call {@link #updateSessionInfo(RoutingSessionInfo)} to update - * session info and call {@link #updateProviderInfo(MediaRoute2ProviderInfo)} to notify - * clients of updated session info. + * After the transfer is finished, call {@link #notifySessionUpdated(RoutingSessionInfo)} + * to update session info. * * @param sessionId id of the session * @param routeId id of the route @@ -344,6 +369,8 @@ public abstract class MediaRoute2ProviderService extends Service { * </p> * * @param preference the new discovery preference + * + * TODO: This method needs tests. */ public void onDiscoveryPreferenceChanged(@NonNull RouteDiscoveryPreference preference) {} @@ -383,7 +410,7 @@ public abstract class MediaRoute2ProviderService extends Service { sessionInfos = new ArrayList<>(mSessionInfo.values()); } try { - mClient.updateState(mProviderInfo, sessionInfos); + mClient.updateState(mProviderInfo); } catch (RemoteException ex) { Log.w(TAG, "Failed to send onProviderInfoUpdated"); } @@ -415,6 +442,7 @@ public abstract class MediaRoute2ProviderService extends Service { MediaRoute2ProviderService.this, packageName, routeId, routeFeature, requestId)); } + @Override public void releaseSession(@NonNull String sessionId) { if (!checkCallerisSystem()) { @@ -424,7 +452,7 @@ public abstract class MediaRoute2ProviderService extends Service { Log.w(TAG, "releaseSession: Ignoring empty sessionId from system service."); return; } - mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::releaseSession, + mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onReleaseSession, MediaRoute2ProviderService.this, sessionId)); } diff --git a/media/java/android/media/MediaTranscodeManager.java b/media/java/android/media/MediaTranscodeManager.java new file mode 100644 index 000000000000..2c431b98fc7a --- /dev/null +++ b/media/java/android/media/MediaTranscodeManager.java @@ -0,0 +1,403 @@ +/* + * Copyright (C) 2019 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.media; + +import android.annotation.CallbackExecutor; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.net.Uri; +import android.util.Log; + +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executor; +import java.util.concurrent.locks.ReentrantLock; + +/** + * MediaTranscodeManager provides an interface to the system's media transcode service. + * Transcode requests are put in a queue and processed in order. When a transcode operation is + * completed the caller is notified via its OnTranscodingFinishedListener. In the meantime the + * caller may use the returned TranscodingJob object to cancel or check the status of a specific + * transcode operation. + * The currently supported media types are video and still images. + * + * TODO(lnilsson): Add sample code when API is settled. + * + * @hide + */ +public final class MediaTranscodeManager { + private static final String TAG = "MediaTranscodeManager"; + + // Invalid ID passed from native means the request was never enqueued. + private static final long ID_INVALID = -1; + + // Events passed from native. + private static final int EVENT_JOB_STARTED = 1; + private static final int EVENT_JOB_PROGRESSED = 2; + private static final int EVENT_JOB_FINISHED = 3; + + @IntDef(prefix = { "EVENT_" }, value = { + EVENT_JOB_STARTED, + EVENT_JOB_PROGRESSED, + EVENT_JOB_FINISHED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Event {} + + private static MediaTranscodeManager sMediaTranscodeManager; + private final ConcurrentMap<Long, TranscodingJob> mPendingTranscodingJobs = + new ConcurrentHashMap<>(); + private final Context mContext; + + /** + * Listener that gets notified when a transcoding operation has finished. + * This listener gets notified regardless of how the operation finished. It is up to the + * listener implementation to check the result and take appropriate action. + */ + @FunctionalInterface + public interface OnTranscodingFinishedListener { + /** + * Called when the transcoding operation has finished. The receiver may use the + * TranscodingJob to check the result, i.e. whether the operation succeeded, was canceled or + * if an error occurred. + * @param transcodingJob The TranscodingJob instance for the finished transcoding operation. + */ + void onTranscodingFinished(@NonNull TranscodingJob transcodingJob); + } + + /** + * Class describing a transcode operation to be performed. The caller uses this class to + * configure a transcoding operation that can then be enqueued using MediaTranscodeManager. + */ + public static final class TranscodingRequest { + private Uri mSrcUri; + private Uri mDstUri; + private MediaFormat mDstFormat; + + private TranscodingRequest(Builder b) { + mSrcUri = b.mSrcUri; + mDstUri = b.mDstUri; + mDstFormat = b.mDstFormat; + } + + /** TranscodingRequest builder class. */ + public static class Builder { + private Uri mSrcUri; + private Uri mDstUri; + private MediaFormat mDstFormat; + + /** + * Specifies the source media file. + * @param uri Content uri for the source media file. + * @return The builder instance. + */ + public Builder setSourceUri(Uri uri) { + mSrcUri = uri; + return this; + } + + /** + * Specifies the destination media file. + * @param uri Content uri for the destination media file. + * @return The builder instance. + */ + public Builder setDestinationUri(Uri uri) { + mDstUri = uri; + return this; + } + + /** + * Specifies the media format of the transcoded media file. + * @param dstFormat MediaFormat containing the desired destination format. + * @return The builder instance. + */ + public Builder setDestinationFormat(MediaFormat dstFormat) { + mDstFormat = dstFormat; + return this; + } + + /** + * Builds a new TranscodingRequest with the configuration set on this builder. + * @return A new TranscodingRequest. + */ + public TranscodingRequest build() { + return new TranscodingRequest(this); + } + } + } + + /** + * Handle to an enqueued transcoding operation. An instance of this class represents a single + * enqueued transcoding operation. The caller can use that instance to query the status or + * progress, and to get the result once the operation has completed. + */ + public static final class TranscodingJob { + /** The job is enqueued but not yet running. */ + public static final int STATUS_PENDING = 1; + /** The job is currently running. */ + public static final int STATUS_RUNNING = 2; + /** The job is finished. */ + public static final int STATUS_FINISHED = 3; + + @IntDef(prefix = { "STATUS_" }, value = { + STATUS_PENDING, + STATUS_RUNNING, + STATUS_FINISHED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Status {} + + /** The job does not have a result yet. */ + public static final int RESULT_NONE = 1; + /** The job completed successfully. */ + public static final int RESULT_SUCCESS = 2; + /** The job encountered an error while running. */ + public static final int RESULT_ERROR = 3; + /** The job was canceled by the caller. */ + public static final int RESULT_CANCELED = 4; + + @IntDef(prefix = { "RESULT_" }, value = { + RESULT_NONE, + RESULT_SUCCESS, + RESULT_ERROR, + RESULT_CANCELED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Result {} + + /** Listener that gets notified when the progress changes. */ + @FunctionalInterface + public interface OnProgressChangedListener { + + /** + * Called when the progress changes. The progress is between 0 and 1, where 0 means + * that the job has not yet started and 1 means that it has finished. + * @param progress The new progress. + */ + void onProgressChanged(float progress); + } + + private final Executor mExecutor; + private final OnTranscodingFinishedListener mListener; + private final ReentrantLock mStatusChangeLock = new ReentrantLock(); + private Executor mProgressChangedExecutor; + private OnProgressChangedListener mProgressChangedListener; + private long mID; + private float mProgress = 0.0f; + private @Status int mStatus = STATUS_PENDING; + private @Result int mResult = RESULT_NONE; + + private TranscodingJob(long id, @NonNull @CallbackExecutor Executor executor, + @NonNull OnTranscodingFinishedListener listener) { + mID = id; + mExecutor = executor; + mListener = listener; + } + + /** + * Set a progress listener. + * @param listener The progress listener. + */ + public void setOnProgressChangedListener(@NonNull @CallbackExecutor Executor executor, + @Nullable OnProgressChangedListener listener) { + mProgressChangedExecutor = executor; + mProgressChangedListener = listener; + } + + /** + * Cancels the transcoding job and notify the listener. If the job happened to finish before + * being canceled this call is effectively a no-op and will not update the result in that + * case. + */ + public void cancel() { + setJobFinished(RESULT_CANCELED); + sMediaTranscodeManager.native_cancelTranscodingRequest(mID); + } + + /** + * Gets the progress of the transcoding job. The progress is between 0 and 1, where 0 means + * that the job has not yet started and 1 means that it is finished. + * @return The progress. + */ + public float getProgress() { + return mProgress; + } + + /** + * Gets the status of the transcoding job. + * @return The status. + */ + public @Status int getStatus() { + return mStatus; + } + + /** + * Gets the result of the transcoding job. + * @return The result. + */ + public @Result int getResult() { + return mResult; + } + + private void setJobStarted() { + mStatus = STATUS_RUNNING; + } + + private void setJobProgress(float newProgress) { + mProgress = newProgress; + + // Notify listener. + OnProgressChangedListener onProgressChangedListener = mProgressChangedListener; + if (onProgressChangedListener != null) { + mProgressChangedExecutor.execute( + () -> onProgressChangedListener.onProgressChanged(mProgress)); + } + } + + private void setJobFinished(int result) { + boolean doNotifyListener = false; + + // Prevent conflicting simultaneous status updates from native (finished) and from the + // caller (cancel). + try { + mStatusChangeLock.lock(); + if (mStatus != STATUS_FINISHED) { + mStatus = STATUS_FINISHED; + mResult = result; + doNotifyListener = true; + } + } finally { + mStatusChangeLock.unlock(); + } + + if (doNotifyListener) { + mExecutor.execute(() -> mListener.onTranscodingFinished(this)); + } + } + + private void processJobEvent(@Event int event, int arg) { + switch (event) { + case EVENT_JOB_STARTED: + setJobStarted(); + break; + case EVENT_JOB_PROGRESSED: + setJobProgress((float) arg / 100); + break; + case EVENT_JOB_FINISHED: + setJobFinished(arg); + break; + default: + Log.e(TAG, "Unsupported event: " + event); + break; + } + } + } + + // Initializes the native library. + private static native void native_init(); + // Requests a new job ID from the native service. + private native long native_requestUniqueJobID(); + // Enqueues a transcoding request to the native service. + private native boolean native_enqueueTranscodingRequest( + long id, @NonNull TranscodingRequest transcodingRequest, @NonNull Context context); + // Cancels an enqueued transcoding request. + private native void native_cancelTranscodingRequest(long id); + + // Private constructor. + private MediaTranscodeManager(@NonNull Context context) { + mContext = context; + } + + // Events posted from the native service. + @SuppressWarnings("unused") + private void postEventFromNative(@Event int event, long id, int arg) { + Log.d(TAG, String.format("postEventFromNative. Event %d, ID %d, arg %d", event, id, arg)); + + TranscodingJob transcodingJob = mPendingTranscodingJobs.get(id); + + // Job IDs are added to the tracking set before the job is enqueued so it should never + // be null unless the service misbehaves. + if (transcodingJob == null) { + Log.e(TAG, "No matching transcode job found for id " + id); + return; + } + + transcodingJob.processJobEvent(event, arg); + } + + /** + * Gets the MediaTranscodeManager singleton instance. + * @param context The application context. + * @return the {@link MediaTranscodeManager} singleton instance. + */ + public static MediaTranscodeManager getInstance(@NonNull Context context) { + Preconditions.checkNotNull(context); + synchronized (MediaTranscodeManager.class) { + if (sMediaTranscodeManager == null) { + sMediaTranscodeManager = new MediaTranscodeManager(context.getApplicationContext()); + } + return sMediaTranscodeManager; + } + } + + /** + * Enqueues a TranscodingRequest for execution. + * @param transcodingRequest The TranscodingRequest to enqueue. + * @param listenerExecutor Executor on which the listener is notified. + * @param listener Listener to get notified when the transcoding job is finished. + * @return A TranscodingJob for this operation. + */ + public @Nullable TranscodingJob enqueueTranscodingRequest( + @NonNull TranscodingRequest transcodingRequest, + @NonNull @CallbackExecutor Executor listenerExecutor, + @NonNull OnTranscodingFinishedListener listener) { + Log.i(TAG, "enqueueTranscodingRequest called."); + Preconditions.checkNotNull(transcodingRequest); + Preconditions.checkNotNull(listenerExecutor); + Preconditions.checkNotNull(listener); + + // Reserve a job ID. + long jobID = native_requestUniqueJobID(); + if (jobID == ID_INVALID) { + return null; + } + + // Add the job to the tracking set. + TranscodingJob transcodingJob = new TranscodingJob(jobID, listenerExecutor, listener); + mPendingTranscodingJobs.put(jobID, transcodingJob); + + // Enqueue the request with the native service. + boolean enqueued = native_enqueueTranscodingRequest(jobID, transcodingRequest, mContext); + if (!enqueued) { + mPendingTranscodingJobs.remove(jobID); + return null; + } + + return transcodingJob; + } + + static { + System.loadLibrary("media_jni"); + native_init(); + } +} diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java index 01f12500b77b..27f02fe528f3 100644 --- a/media/java/android/media/audiopolicy/AudioPolicy.java +++ b/media/java/android/media/audiopolicy/AudioPolicy.java @@ -719,9 +719,14 @@ public class AudioPolicy { if (track == null) { break; } - // TODO: add synchronous versions - track.stop(); - track.flush(); + try { + // TODO: add synchronous versions + track.stop(); + track.flush(); + } catch (IllegalStateException e) { + // ignore exception, AudioTrack could have already been stopped or + // released by the user of the AudioPolicy + } } } if (mCaptors != null) { @@ -730,8 +735,13 @@ public class AudioPolicy { if (record == null) { break; } - // TODO: if needed: implement an invalidate method - record.stop(); + try { + // TODO: if needed: implement an invalidate method + record.stop(); + } catch (IllegalStateException e) { + // ignore exception, AudioRecord could have already been stopped or + // released by the user of the AudioPolicy + } } } } diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 862489f4ed8d..e3dfaeb10948 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -16,6 +16,7 @@ package android.media.tv.tuner; +import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -32,11 +33,13 @@ import android.media.tv.tuner.filter.TimeFilter; import android.media.tv.tuner.frontend.FrontendCallback; import android.media.tv.tuner.frontend.FrontendInfo; import android.media.tv.tuner.frontend.FrontendStatus; +import android.media.tv.tuner.frontend.ScanCallback; import android.os.Handler; import android.os.Looper; import android.os.Message; import java.util.List; +import java.util.concurrent.Executor; /** * This class is used to interact with hardware tuners devices. @@ -70,6 +73,10 @@ public final class Tuner implements AutoCloseable { private List<Integer> mLnbIds; private Lnb mLnb; + @Nullable + private ScanCallback mScanCallback; + @Nullable + private Executor mScanCallbackExecutor; /** * Constructs a Tuner instance. @@ -231,29 +238,6 @@ public final class Tuner implements AutoCloseable { private Frontend(int id) { mId = id; } - - public void setCallback(@Nullable FrontendCallback callback, @Nullable Handler handler) { - mCallback = callback; - - if (mCallback == null) { - return; - } - - if (handler == null) { - // use default looper if handler is null - if (mHandler == null) { - mHandler = createEventHandler(); - } - return; - } - - Looper looper = handler.getLooper(); - if (mHandler != null && mHandler.getLooper() == looper) { - // the same looper. reuse mHandler - return; - } - mHandler = new EventHandler(looper); - } } /** @@ -286,18 +270,32 @@ public final class Tuner implements AutoCloseable { * Scan channels. * @hide */ - public int scan(@NonNull FrontendSettings settings, @FrontendScanType int scanType) { + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + public int scan(@NonNull FrontendSettings settings, @FrontendScanType int scanType, + @NonNull @CallbackExecutor Executor executor, @NonNull ScanCallback scanCallback) { + mScanCallback = scanCallback; + mScanCallbackExecutor = executor; return nativeScan(settings.getType(), settings, scanType); } /** * Stops a previous scanning. * - * If the method completes successfully, the frontend stop previous scanning. + * <p> + * The {@link ScanCallback} and it's {@link Executor} will be removed. + * + * <p> + * If the method completes successfully, the frontend stopped previous scanning. + * * @hide */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int stopScan() { - return nativeStopScan(); + TunerUtils.checkTunerPermission(mContext); + int retVal = nativeStopScan(); + mScanCallback = null; + mScanCallbackExecutor = null; + return retVal; } /** diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java index c2d6c58c6558..4532122034ed 100644 --- a/media/java/android/media/tv/tuner/TunerConstants.java +++ b/media/java/android/media/tv/tuner/TunerConstants.java @@ -1015,10 +1015,13 @@ public final class TunerConstants { Constants.FrontendAtsc3DemodOutputFormat.BASEBAND_PACKET; /** @hide */ - @IntDef({FRONTEND_DVBS_STANDARD_AUTO, FRONTEND_DVBS_STANDARD_S, FRONTEND_DVBS_STANDARD_S2, - FRONTEND_DVBS_STANDARD_S2X}) + @IntDef(prefix = "FRONTEND_DVBS_STANDARD", + value = {FRONTEND_DVBS_STANDARD_AUTO, FRONTEND_DVBS_STANDARD_S, + FRONTEND_DVBS_STANDARD_S2, + FRONTEND_DVBS_STANDARD_S2X}) @Retention(RetentionPolicy.SOURCE) - public @interface FrontendDvbsStandard {} + public @interface FrontendDvbsStandard { + } /** @hide */ public static final int FRONTEND_DVBS_STANDARD_AUTO = Constants.FrontendDvbsStandard.AUTO; /** @hide */ @@ -1210,6 +1213,20 @@ public final class TunerConstants { Constants.FrontendDvbtGuardInterval.INTERVAL_19_256; /** @hide */ + @IntDef(prefix = "FRONTEND_DVBT_STANDARD", + value = {FRONTEND_DVBT_STANDARD_AUTO, FRONTEND_DVBT_STANDARD_T, + FRONTEND_DVBT_STANDARD_T2} + ) + @Retention(RetentionPolicy.SOURCE) + public @interface FrontendDvbtStandard {} + /** @hide */ + public static final int FRONTEND_DVBT_STANDARD_AUTO = Constants.FrontendDvbtStandard.AUTO; + /** @hide */ + public static final int FRONTEND_DVBT_STANDARD_T = Constants.FrontendDvbtStandard.T; + /** @hide */ + public static final int FRONTEND_DVBT_STANDARD_T2 = Constants.FrontendDvbtStandard.T2; + + /** @hide */ @IntDef({FRONTEND_ISDBS_CODERATE_UNDEFINED, FRONTEND_ISDBS_CODERATE_AUTO, FRONTEND_ISDBS_CODERATE_1_2, FRONTEND_ISDBS_CODERATE_2_3, FRONTEND_ISDBS_CODERATE_3_4, FRONTEND_ISDBS_CODERATE_5_6, FRONTEND_ISDBS_CODERATE_7_8}) diff --git a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java index 99b10cde34f9..6496627cd1d4 100644 --- a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java +++ b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java @@ -18,6 +18,7 @@ package android.media.tv.tuner.filter; import android.annotation.IntDef; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.hardware.tv.tuner.V1_0.Constants; import java.lang.annotation.Retention; @@ -28,6 +29,7 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ +@SystemApi public abstract class FilterConfiguration { /** @hide */ @@ -57,7 +59,7 @@ public abstract class FilterConfiguration { public static final int FILTER_TYPE_ALP = Constants.DemuxFilterMainType.ALP; @Nullable - private final Settings mSettings; + /* package */ final Settings mSettings; /* package */ FilterConfiguration(Settings settings) { mSettings = settings; diff --git a/media/java/android/media/tv/tuner/filter/PesSettings.java b/media/java/android/media/tv/tuner/filter/PesSettings.java index f38abf12e120..bfa1f8c67d97 100644 --- a/media/java/android/media/tv/tuner/filter/PesSettings.java +++ b/media/java/android/media/tv/tuner/filter/PesSettings.java @@ -17,6 +17,9 @@ package android.media.tv.tuner.filter; import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.content.Context; import android.media.tv.tuner.TunerConstants; import android.media.tv.tuner.TunerUtils; import android.media.tv.tuner.filter.FilterConfiguration.FilterType; @@ -26,6 +29,7 @@ import android.media.tv.tuner.filter.FilterConfiguration.FilterType; * * @hide */ +@SystemApi public class PesSettings extends Settings { private final int mStreamId; private final boolean mIsRaw; @@ -37,12 +41,32 @@ public class PesSettings extends Settings { } /** + * Gets stream ID. + */ + public int getStreamId() { + return mStreamId; + } + + /** + * Returns whether the data is raw. + * + * @return {@code true} if the data is raw. Filter sends onFilterStatus callback + * instead of onFilterEvent for raw data. {@code false} otherwise. + */ + public boolean isRaw() { + return mIsRaw; + } + + /** * Creates a builder for {@link PesSettings}. * * @param mainType the filter main type of the settings. + * @param context the context of the caller. */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) @NonNull - public static Builder newBuilder(@FilterType int mainType) { + public static Builder builder(@NonNull Context context, @FilterType int mainType) { + TunerUtils.checkTunerPermission(context); return new Builder(mainType); } @@ -70,13 +94,13 @@ public class PesSettings extends Settings { } /** - * Sets whether it's raw. + * Sets whether the data is raw. * * @param isRaw {@code true} if the data is raw. Filter sends onFilterStatus callback * instead of onFilterEvent for raw data. {@code false} otherwise. */ @NonNull - public Builder setIsRaw(boolean isRaw) { + public Builder setRaw(boolean isRaw) { mIsRaw = isRaw; return this; } diff --git a/media/java/android/media/tv/tuner/filter/Settings.java b/media/java/android/media/tv/tuner/filter/Settings.java index 146aca74ce0e..91559260031c 100644 --- a/media/java/android/media/tv/tuner/filter/Settings.java +++ b/media/java/android/media/tv/tuner/filter/Settings.java @@ -16,11 +16,14 @@ package android.media.tv.tuner.filter; +import android.annotation.SystemApi; + /** * Settings for filters of different subtypes. * * @hide */ +@SystemApi public abstract class Settings { private final int mType; diff --git a/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java index d0241b6aba09..5c38cfa70eb3 100644 --- a/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java +++ b/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java @@ -17,12 +17,18 @@ package android.media.tv.tuner.filter; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.content.Context; +import android.media.tv.tuner.TunerUtils; /** * Filter configuration for a TS filter. * * @hide */ +@SystemApi public class TsFilterConfiguration extends FilterConfiguration { private final int mTpid; @@ -37,10 +43,28 @@ public class TsFilterConfiguration extends FilterConfiguration { } /** + * Gets the {@link Settings} object of this filter configuration. + */ + @Nullable + public Settings getSettings() { + return mSettings; + } + /** + * Gets Tag Protocol ID. + */ + public int getTpid() { + return mTpid; + } + + /** * Creates a builder for {@link TsFilterConfiguration}. + * + * @param context the context of the caller. */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) @NonNull - public static Builder newBuilder() { + public static Builder builder(@NonNull Context context) { + TunerUtils.checkTunerPermission(context); return new Builder(); } @@ -51,6 +75,9 @@ public class TsFilterConfiguration extends FilterConfiguration { private Settings mSettings; private int mTpid; + private Builder() { + } + /** * Sets filter settings. * diff --git a/media/java/android/media/tv/tuner/frontend/FrontendCallback.java b/media/java/android/media/tv/tuner/frontend/FrontendCallback.java index 0992eb665330..9c4f4606a9bc 100644 --- a/media/java/android/media/tv/tuner/frontend/FrontendCallback.java +++ b/media/java/android/media/tv/tuner/frontend/FrontendCallback.java @@ -27,10 +27,4 @@ public interface FrontendCallback { * Invoked when there is a frontend event. */ void onEvent(int frontendEventType); - - /** - * Invoked when there is a scan message. - * @param msg - */ - void onScanMessage(ScanMessage msg); } diff --git a/media/java/android/media/tv/tuner/frontend/ScanCallback.java b/media/java/android/media/tv/tuner/frontend/ScanCallback.java new file mode 100644 index 000000000000..8118fcc0e900 --- /dev/null +++ b/media/java/android/media/tv/tuner/frontend/ScanCallback.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2020 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.media.tv.tuner.frontend; + +import android.media.tv.tuner.TunerConstants; + +/** + * Scan callback. + * + * @hide + */ +public interface ScanCallback { + /** Scan locked the signal. */ + void onLocked(boolean isLocked); + + /** Scan stopped. */ + void onEnd(boolean isEnd); + + /** scan progress percent (0..100) */ + void onProgress(int percent); + + /** Signal frequency in Hertz */ + void onFrequencyReport(int frequency); + + /** Symbols per second */ + void onSymbolRate(int rate); + + /** Locked Plp Ids for DVBT2 frontend. */ + void onPlpIds(int[] plpIds); + + /** Locked group Ids for DVBT2 frontend. */ + void onGroupIds(int[] groupIds); + + /** Stream Ids. */ + void onInputStreamIds(int[] inputStreamIds); + + /** Locked signal standard. */ + void onDvbsStandard(@TunerConstants.FrontendDvbsStandard int dvbsStandandard); + + /** Locked signal standard. */ + void onDvbtStandard(@TunerConstants.FrontendDvbtStandard int dvbtStandard); + + /** PLP status in a tuned frequency band for ATSC3 frontend. */ + void onAtsc3PlpInfos(Atsc3PlpInfo[] atsc3PlpInfos); + + /** PLP information for ATSC3. */ + class Atsc3PlpInfo { + private final int mPlpId; + private final boolean mLlsFlag; + + private Atsc3PlpInfo(int plpId, boolean llsFlag) { + mPlpId = plpId; + mLlsFlag = llsFlag; + } + + /** Gets PLP IDs. */ + public int getPlpId() { + return mPlpId; + } + + /** Gets LLS flag. */ + public boolean getLlsFlag() { + return mLlsFlag; + } + } +} diff --git a/media/java/android/media/tv/tuner/frontend/ScanMessage.java b/media/java/android/media/tv/tuner/frontend/ScanMessage.java deleted file mode 100644 index dd687dd2959c..000000000000 --- a/media/java/android/media/tv/tuner/frontend/ScanMessage.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2020 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.media.tv.tuner.frontend; - -import android.annotation.IntDef; -import android.hardware.tv.tuner.V1_0.Constants; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Message from frontend during scan operations. - * - * @hide - */ -public class ScanMessage { - - /** @hide */ - @IntDef({ - LOCKED, - END, - PROGRESS_PERCENT, - FREQUENCY, - SYMBOL_RATE, - PLP_IDS, - GROUP_IDS, - INPUT_STREAM_IDS, - STANDARD, - ATSC3_PLP_INFO - }) - @Retention(RetentionPolicy.SOURCE) - public @interface Type {} - /** @hide */ - public static final int LOCKED = Constants.FrontendScanMessageType.LOCKED; - /** @hide */ - public static final int END = Constants.FrontendScanMessageType.END; - /** @hide */ - public static final int PROGRESS_PERCENT = Constants.FrontendScanMessageType.PROGRESS_PERCENT; - /** @hide */ - public static final int FREQUENCY = Constants.FrontendScanMessageType.FREQUENCY; - /** @hide */ - public static final int SYMBOL_RATE = Constants.FrontendScanMessageType.SYMBOL_RATE; - /** @hide */ - public static final int PLP_IDS = Constants.FrontendScanMessageType.PLP_IDS; - /** @hide */ - public static final int GROUP_IDS = Constants.FrontendScanMessageType.GROUP_IDS; - /** @hide */ - public static final int INPUT_STREAM_IDS = Constants.FrontendScanMessageType.INPUT_STREAM_IDS; - /** @hide */ - public static final int STANDARD = Constants.FrontendScanMessageType.STANDARD; - /** @hide */ - public static final int ATSC3_PLP_INFO = Constants.FrontendScanMessageType.ATSC3_PLP_INFO; - - private final int mType; - private final Object mValue; - - private ScanMessage(int type, Object value) { - mType = type; - mValue = value; - } - - /** Gets scan message type. */ - @Type - public int getMessageType() { - return mType; - } - /** Message indicates whether frontend is locked or not. */ - public boolean getIsLocked() { - if (mType != LOCKED) { - throw new IllegalStateException(); - } - return (Boolean) mValue; - } - /** Message indicates whether the scan has reached the end or not. */ - public boolean getIsEnd() { - if (mType != END) { - throw new IllegalStateException(); - } - return (Boolean) mValue; - } - /** Progress message in percent. */ - public int getProgressPercent() { - if (mType != PROGRESS_PERCENT) { - throw new IllegalStateException(); - } - return (Integer) mValue; - } - /** Gets frequency. */ - public int getFrequency() { - if (mType != FREQUENCY) { - throw new IllegalStateException(); - } - return (Integer) mValue; - } - /** Gets symbol rate. */ - public int getSymbolRate() { - if (mType != SYMBOL_RATE) { - throw new IllegalStateException(); - } - return (Integer) mValue; - } - /** Gets PLP IDs. */ - public int[] getPlpIds() { - if (mType != PLP_IDS) { - throw new IllegalStateException(); - } - return (int[]) mValue; - } - /** Gets group IDs. */ - public int[] getGroupIds() { - if (mType != GROUP_IDS) { - throw new IllegalStateException(); - } - return (int[]) mValue; - } - /** Gets Input stream IDs. */ - public int[] getInputStreamIds() { - if (mType != INPUT_STREAM_IDS) { - throw new IllegalStateException(); - } - return (int[]) mValue; - } - /** Gets the DVB-T or DVB-S standard. */ - public int getStandard() { - if (mType != STANDARD) { - throw new IllegalStateException(); - } - return (int) mValue; - } - - /** Gets PLP information for ATSC3. */ - public Atsc3PlpInfo[] getAtsc3PlpInfos() { - if (mType != ATSC3_PLP_INFO) { - throw new IllegalStateException(); - } - return (Atsc3PlpInfo[]) mValue; - } - - /** PLP information for ATSC3. */ - public static class Atsc3PlpInfo { - private final int mPlpId; - private final boolean mLlsFlag; - - private Atsc3PlpInfo(int plpId, boolean llsFlag) { - mPlpId = plpId; - mLlsFlag = llsFlag; - } - - /** Gets PLP IDs. */ - public int getPlpId() { - return mPlpId; - } - /** Gets LLS flag. */ - public boolean getLlsFlag() { - return mLlsFlag; - } - } -} diff --git a/media/jni/Android.bp b/media/jni/Android.bp index 536a061190d7..aeacd8f63cb0 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -19,6 +19,7 @@ cc_library_shared { "android_media_MediaProfiles.cpp", "android_media_MediaRecorder.cpp", "android_media_MediaSync.cpp", + "android_media_MediaTranscodeManager.cpp", "android_media_ResampleInputStream.cpp", "android_media_Streams.cpp", "android_media_SyncParams.cpp", diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 963b650292e4..5cb42a9a96cc 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -1453,6 +1453,7 @@ extern int register_android_media_MediaProfiles(JNIEnv *env); extern int register_android_mtp_MtpDatabase(JNIEnv *env); extern int register_android_mtp_MtpDevice(JNIEnv *env); extern int register_android_mtp_MtpServer(JNIEnv *env); +extern int register_android_media_MediaTranscodeManager(JNIEnv *env); jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { @@ -1565,6 +1566,11 @@ jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) goto bail; } + if (register_android_media_MediaTranscodeManager(env) < 0) { + ALOGE("ERROR: MediaTranscodeManager native registration failed"); + goto bail; + } + /* success -- return valid version number */ result = JNI_VERSION_1_4; diff --git a/media/jni/android_media_MediaTranscodeManager.cpp b/media/jni/android_media_MediaTranscodeManager.cpp new file mode 100644 index 000000000000..0b4048c1170c --- /dev/null +++ b/media/jni/android_media_MediaTranscodeManager.cpp @@ -0,0 +1,102 @@ +/* + * Copyright 2019, 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. + */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "MediaTranscodeManager_JNI" + +#include "android_runtime/AndroidRuntime.h" +#include "jni.h" + +#include <nativehelper/JNIHelp.h> +#include <utils/Log.h> + +namespace { + +// NOTE: Keep these enums in sync with their equivalents in MediaTranscodeManager.java. +enum { + ID_INVALID = -1 +}; + +enum { + EVENT_JOB_STARTED = 1, + EVENT_JOB_PROGRESSED = 2, + EVENT_JOB_FINISHED = 3, +}; + +enum { + RESULT_NONE = 1, + RESULT_SUCCESS = 2, + RESULT_ERROR = 3, + RESULT_CANCELED = 4, +}; + +struct { + jmethodID postEventFromNative; +} gMediaTranscodeManagerClassInfo; + +using namespace android; + +void android_media_MediaTranscodeManager_native_init(JNIEnv *env, jclass clazz) { + ALOGV("android_media_MediaTranscodeManager_native_init"); + + gMediaTranscodeManagerClassInfo.postEventFromNative = env->GetMethodID( + clazz, "postEventFromNative", "(IJI)V"); + LOG_ALWAYS_FATAL_IF(gMediaTranscodeManagerClassInfo.postEventFromNative == NULL, + "can't find android/media/MediaTranscodeManager.postEventFromNative"); +} + +jlong android_media_MediaTranscodeManager_requestUniqueJobID( + JNIEnv *env __unused, jobject thiz __unused) { + ALOGV("android_media_MediaTranscodeManager_reserveUniqueJobID"); + static std::atomic_int32_t sJobIDCounter{0}; + jlong id = (jlong)++sJobIDCounter; + return id; +} + +jboolean android_media_MediaTranscodeManager_enqueueTranscodingRequest( + JNIEnv *env, jobject thiz, jlong id, jobject request, jobject context __unused) { + ALOGV("android_media_MediaTranscodeManager_enqueueTranscodingRequest"); + if (!request) { + return ID_INVALID; + } + + env->CallVoidMethod(thiz, gMediaTranscodeManagerClassInfo.postEventFromNative, + EVENT_JOB_FINISHED, id, RESULT_ERROR); + return true; +} + +void android_media_MediaTranscodeManager_cancelTranscodingRequest( + JNIEnv *env __unused, jobject thiz __unused, jlong jobID __unused) { + ALOGV("android_media_MediaTranscodeManager_cancelTranscodingRequest"); +} + +const JNINativeMethod gMethods[] = { + { "native_init", "()V", + (void *)android_media_MediaTranscodeManager_native_init }, + { "native_requestUniqueJobID", "()J", + (void *)android_media_MediaTranscodeManager_requestUniqueJobID }, + { "native_enqueueTranscodingRequest", + "(JLandroid/media/MediaTranscodeManager$TranscodingRequest;Landroid/content/Context;)Z", + (void *)android_media_MediaTranscodeManager_enqueueTranscodingRequest }, + { "native_cancelTranscodingRequest", "(J)V", + (void *)android_media_MediaTranscodeManager_cancelTranscodingRequest }, +}; + +} // namespace anonymous + +int register_android_media_MediaTranscodeManager(JNIEnv *env) { + return AndroidRuntime::registerNativeMethods(env, + "android/media/MediaTranscodeManager", gMethods, NELEM(gMethods)); +} diff --git a/media/tests/MediaFrameworkTest/Android.bp b/media/tests/MediaFrameworkTest/Android.bp index f0fbc509cc9d..ecbe2b3eb8b7 100644 --- a/media/tests/MediaFrameworkTest/Android.bp +++ b/media/tests/MediaFrameworkTest/Android.bp @@ -7,6 +7,7 @@ android_test { ], static_libs: [ "mockito-target-minus-junit4", + "androidx.test.ext.junit", "androidx.test.rules", "android-ex-camera2", ], diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediatranscodemanager/MediaTranscodeManagerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediatranscodemanager/MediaTranscodeManagerTest.java new file mode 100644 index 000000000000..eeda50e5c095 --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediatranscodemanager/MediaTranscodeManagerTest.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2019 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.mediaframeworktest.functional.mediatranscodemanager; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import android.media.MediaTranscodeManager; +import android.util.Log; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +public class MediaTranscodeManagerTest { + private static final String TAG = "MediaTranscodeManagerTest"; + + /** The time to wait for the transcode operation to complete before failing the test. */ + private static final int TRANSCODE_TIMEOUT_SECONDS = 2; + + @Test + public void testMediaTranscodeManager() throws InterruptedException { + Log.d(TAG, "Starting: testMediaTranscodeManager"); + + Semaphore transcodeCompleteSemaphore = new Semaphore(0); + MediaTranscodeManager.TranscodingRequest request = + new MediaTranscodeManager.TranscodingRequest.Builder().build(); + Executor listenerExecutor = Executors.newSingleThreadExecutor(); + + MediaTranscodeManager mediaTranscodeManager = + MediaTranscodeManager.getInstance(ApplicationProvider.getApplicationContext()); + assertNotNull(mediaTranscodeManager); + + MediaTranscodeManager.TranscodingJob job; + job = mediaTranscodeManager.enqueueTranscodingRequest(request, listenerExecutor, + transcodingJob -> { + Log.d(TAG, "Transcoding completed with result: " + transcodingJob.getResult()); + transcodeCompleteSemaphore.release(); + }); + assertNotNull(job); + + job.setOnProgressChangedListener( + listenerExecutor, progress -> Log.d(TAG, "Progress: " + progress)); + + if (job != null) { + Log.d(TAG, "testMediaTranscodeManager - Waiting for transcode to complete."); + boolean finishedOnTime = transcodeCompleteSemaphore.tryAcquire( + TRANSCODE_TIMEOUT_SECONDS, TimeUnit.SECONDS); + assertTrue("Transcode failed to complete in time.", finishedOnTime); + } + } +} diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java index 221783b1c97d..ed93112d5288 100644 --- a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java +++ b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java @@ -172,7 +172,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService MediaRoute2Info route = mRoutes.get(routeId); if (route == null || TextUtils.equals(ROUTE_ID3_SESSION_CREATION_FAILED, routeId)) { // Tell the router that session cannot be created by passing null as sessionInfo. - notifySessionCreated(/* sessionInfo= */ null, requestId); + notifySessionCreationFailed(requestId); return; } maybeDeselectRoute(routeId); @@ -196,8 +196,13 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService } @Override - public void onDestroySession(String sessionId, RoutingSessionInfo lastSessionInfo) { - for (String routeId : lastSessionInfo.getSelectedRoutes()) { + public void onReleaseSession(String sessionId) { + RoutingSessionInfo sessionInfo = getSessionInfo(sessionId); + if (sessionInfo == null) { + return; + } + + for (String routeId : sessionInfo.getSelectedRoutes()) { mRouteIdToSessionId.remove(routeId); MediaRoute2Info route = mRoutes.get(routeId); if (route != null) { @@ -206,6 +211,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService .build()); } } + notifySessionReleased(sessionId); } @Override @@ -227,8 +233,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService .removeSelectableRoute(routeId) .addDeselectableRoute(routeId) .build(); - updateSessionInfo(newSessionInfo); - notifySessionInfoChanged(newSessionInfo); + notifySessionUpdated(newSessionInfo); } @Override @@ -247,7 +252,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService .build()); if (sessionInfo.getSelectedRoutes().size() == 1) { - releaseSession(sessionId); + notifySessionReleased(sessionId); return; } @@ -256,8 +261,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService .addSelectableRoute(routeId) .removeDeselectableRoute(routeId) .build(); - updateSessionInfo(newSessionInfo); - notifySessionInfoChanged(newSessionInfo); + notifySessionUpdated(newSessionInfo); } @Override @@ -269,8 +273,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService .removeDeselectableRoute(routeId) .removeTransferrableRoute(routeId) .build(); - updateSessionInfo(newSessionInfo); - notifySessionInfoChanged(newSessionInfo); + notifySessionUpdated(newSessionInfo); } void maybeDeselectRoute(String routeId) { diff --git a/native/graphics/jni/bitmap.cpp b/native/graphics/jni/bitmap.cpp index 1aebeaf1e7e8..26c7f8d709e7 100644 --- a/native/graphics/jni/bitmap.cpp +++ b/native/graphics/jni/bitmap.cpp @@ -16,6 +16,7 @@ #include <android/bitmap.h> #include <android/graphics/bitmap.h> +#include <android/data_space.h> int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, AndroidBitmapInfo* info) { @@ -29,6 +30,15 @@ int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, return ANDROID_BITMAP_RESULT_SUCCESS; } +int32_t AndroidBitmap_getDataSpace(JNIEnv* env, jobject jbitmap) { + if (NULL == env || NULL == jbitmap) { + return ADATASPACE_UNKNOWN; // Or return a real error? + } + + android::graphics::Bitmap bitmap(env, jbitmap); + return bitmap.getDataSpace(); +} + int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr) { if (NULL == env || NULL == jbitmap) { return ANDROID_BITMAP_RESULT_BAD_PARAMETER; diff --git a/native/graphics/jni/libjnigraphics.map.txt b/native/graphics/jni/libjnigraphics.map.txt index bdd7f63b2d78..832770ffb97e 100644 --- a/native/graphics/jni/libjnigraphics.map.txt +++ b/native/graphics/jni/libjnigraphics.map.txt @@ -18,6 +18,7 @@ LIBJNIGRAPHICS { AImageDecoderHeaderInfo_isAnimated; AImageDecoderHeaderInfo_getAndroidBitmapFormat; AndroidBitmap_getInfo; + AndroidBitmap_getDataSpace; AndroidBitmap_lockPixels; AndroidBitmap_unlockPixels; local: diff --git a/packages/CarSystemUI/res/layout/sysui_primary_window.xml b/packages/CarSystemUI/res/layout/sysui_primary_window.xml index 309d9ef3ccfd..cc36e87eb480 100644 --- a/packages/CarSystemUI/res/layout/sysui_primary_window.xml +++ b/packages/CarSystemUI/res/layout/sysui_primary_window.xml @@ -15,9 +15,16 @@ ~ limitations under the License. --> +<!-- Fullscreen views in sysui should be listed here in increasing Z order. --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:background="@android:color/transparent" android:layout_width="match_parent" android:layout_height="match_parent"> + + <ViewStub android:id="@+id/fullscreen_user_switcher_stub" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout="@layout/car_fullscreen_user_switcher"/> + </FrameLayout>
\ No newline at end of file diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java index 6ec385438e23..cfe1c702663e 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java @@ -22,7 +22,7 @@ import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; -import com.android.systemui.statusbar.notification.collection.NotificationRowBinder; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; import com.android.systemui.statusbar.notification.logging.NotifLog; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.util.leak.LeakDetector; diff --git a/packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java b/packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java index e3e9ab75e3a2..c7e14d677b04 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java @@ -54,6 +54,7 @@ public class SystemUIPrimaryWindowController implements private ViewGroup mBaseLayout; private WindowManager.LayoutParams mLp; private WindowManager.LayoutParams mLpChanged; + private boolean mIsAttached = false; @Inject public SystemUIPrimaryWindowController( @@ -86,8 +87,17 @@ public class SystemUIPrimaryWindowController implements return mBaseLayout; } + /** Returns {@code true} if the window is already attached. */ + public boolean isAttached() { + return mIsAttached; + } + /** Attaches the window to the window manager. */ public void attach() { + if (mIsAttached) { + return; + } + mIsAttached = true; // Now that the status bar window encompasses the sliding panel and its // translucent backdrop, the entire thing is made TRANSLUCENT and is // hardware-accelerated. @@ -98,13 +108,14 @@ public class SystemUIPrimaryWindowController implements WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, + | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT); mLp.token = new Binder(); mLp.gravity = Gravity.TOP; mLp.setFitWindowInsetsTypes(/* types= */ 0); mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; - mLp.setTitle("NotificationShade"); + mLp.setTitle("SystemUIPrimaryWindow"); mLp.packageName = mContext.getPackageName(); mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; @@ -118,8 +129,11 @@ public class SystemUIPrimaryWindowController implements // TODO: Update this so that the windowing type gets the full height of the display // when we use MATCH_PARENT. mLpChanged.height = mDisplayHeight + mNavBarHeight; + mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; } else { mLpChanged.height = mStatusBarHeight; + // TODO: Allow touches to go through to the status bar to handle notification panel. + mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; } updateWindow(); } @@ -131,7 +145,9 @@ public class SystemUIPrimaryWindowController implements private void updateWindow() { if (mLp != null && mLp.copyFrom(mLpChanged) != 0) { - mWindowManager.updateViewLayout(mBaseLayout, mLp); + if (isAttached()) { + mWindowManager.updateViewLayout(mBaseLayout, mLp); + } } } } diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index 4521f5fb470e..18485dc283f0 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -67,6 +67,7 @@ import com.android.systemui.bubbles.BubbleController; import com.android.systemui.car.CarDeviceProvisionedController; import com.android.systemui.car.CarDeviceProvisionedListener; import com.android.systemui.car.CarServiceProvider; +import com.android.systemui.car.SystemUIPrimaryWindowController; import com.android.systemui.classifier.FalsingLog; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dagger.qualifiers.UiBackground; @@ -106,8 +107,8 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl; -import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; +import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.phone.AutoHideController; @@ -168,6 +169,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt // acceleration rate for the fling animation private static final float FLING_SPEED_UP_FACTOR = 0.6f; + private final UserSwitcherController mUserSwitcherController; private final ScrimController mScrimController; private final LockscreenLockIconController mLockscreenLockIconController; @@ -177,17 +179,16 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt private float mBackgroundAlphaDiff; private float mInitialBackgroundAlpha; - private final Lazy<FullscreenUserSwitcher> mFullscreenUserSwitcherLazy; - private FullscreenUserSwitcher mFullscreenUserSwitcher; - private CarBatteryController mCarBatteryController; private BatteryMeterView mBatteryMeterView; private Drawable mNotificationPanelBackground; private final Object mQueueLock = new Object(); + private final SystemUIPrimaryWindowController mSystemUIPrimaryWindowController; private final CarNavigationBarController mCarNavigationBarController; private final FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder; private final Lazy<PowerManagerHelper> mPowerManagerHelperLazy; + private final FullscreenUserSwitcher mFullscreenUserSwitcher; private final ShadeController mShadeController; private final CarServiceProvider mCarServiceProvider; private final CarDeviceProvisionedController mCarDeviceProvisionedController; @@ -268,7 +269,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt HeadsUpManagerPhone headsUpManagerPhone, DynamicPrivacyController dynamicPrivacyController, BypassHeadsUpNotifier bypassHeadsUpNotifier, - Lazy<NewNotifPipeline> newNotifPipeline, + Lazy<NotifPipelineInitializer> notifPipelineInitializer, FalsingManager falsingManager, BroadcastDispatcher broadcastDispatcher, RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, @@ -338,7 +339,8 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt /* Car Settings injected components. */ CarServiceProvider carServiceProvider, Lazy<PowerManagerHelper> powerManagerHelperLazy, - Lazy<FullscreenUserSwitcher> fullscreenUserSwitcherLazy, + FullscreenUserSwitcher fullscreenUserSwitcher, + SystemUIPrimaryWindowController systemUIPrimaryWindowController, CarNavigationBarController carNavigationBarController, FlingAnimationUtils.Builder flingAnimationUtilsBuilder) { super( @@ -355,7 +357,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt headsUpManagerPhone, dynamicPrivacyController, bypassHeadsUpNotifier, - newNotifPipeline, + notifPipelineInitializer, falsingManager, broadcastDispatcher, remoteInputQuickSettingsDisabler, @@ -422,6 +424,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt userInfoControllerImpl, notificationRowBinder, dismissCallbackRegistry); + mUserSwitcherController = userSwitcherController; mScrimController = scrimController; mLockscreenLockIconController = lockscreenLockIconController; mCarDeviceProvisionedController = @@ -429,7 +432,8 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt mShadeController = shadeController; mCarServiceProvider = carServiceProvider; mPowerManagerHelperLazy = powerManagerHelperLazy; - mFullscreenUserSwitcherLazy = fullscreenUserSwitcherLazy; + mFullscreenUserSwitcher = fullscreenUserSwitcher; + mSystemUIPrimaryWindowController = systemUIPrimaryWindowController; mCarNavigationBarController = carNavigationBarController; mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder; } @@ -444,6 +448,13 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt mScreenLifecycle = Dependency.get(ScreenLifecycle.class); mScreenLifecycle.addObserver(mScreenObserver); + // TODO: Remove the setup of user switcher from Car Status Bar. + mSystemUIPrimaryWindowController.attach(); + mFullscreenUserSwitcher.setStatusBar(this); + mFullscreenUserSwitcher.setContainer( + mSystemUIPrimaryWindowController.getBaseLayout().findViewById( + R.id.fullscreen_user_switcher_stub)); + // Notification bar related setup. mInitialBackgroundAlpha = (float) mContext.getResources().getInteger( R.integer.config_initialNotificationBackgroundAlpha) / 100; @@ -510,16 +521,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt }); } - /** - * Allows for showing or hiding just the navigation bars. This is indented to be used when - * the full screen user selector is shown. - */ - void setNavBarVisibility(@View.Visibility int visibility) { - mCarNavigationBarController.setBottomWindowVisibility(visibility); - mCarNavigationBarController.setLeftWindowVisibility(visibility); - mCarNavigationBarController.setRightWindowVisibility(visibility); - } - @Override public boolean hideKeyguard() { boolean result = super.hideKeyguard(); @@ -924,9 +925,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt + " scroll " + mStackScroller.getScrollX() + "," + mStackScroller.getScrollY()); } - - pw.print(" mFullscreenUserSwitcher="); - pw.println(mFullscreenUserSwitcher); pw.print(" mCarBatteryController="); pw.println(mCarBatteryController); pw.print(" mBatteryMeterView="); @@ -972,14 +970,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt @Override protected void createUserSwitcher() { - UserSwitcherController userSwitcherController = - Dependency.get(UserSwitcherController.class); - if (userSwitcherController.useFullscreenUserSwitcher()) { - mFullscreenUserSwitcher = mFullscreenUserSwitcherLazy.get(); - mFullscreenUserSwitcher.setStatusBar(this); - mFullscreenUserSwitcher.setContainer( - mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub)); - } else { + if (!mUserSwitcherController.useFullscreenUserSwitcher()) { super.createUserSwitcher(); } } @@ -996,25 +987,12 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt super.onStateChanged(newState); if (newState != StatusBarState.FULLSCREEN_USER_SWITCHER) { - hideUserSwitcher(); + mFullscreenUserSwitcher.hide(); } else { dismissKeyguardWhenUserSwitcherNotDisplayed(); } } - /** Makes the full screen user switcher visible, if applicable. */ - public void showUserSwitcher() { - if (mFullscreenUserSwitcher != null && mState == StatusBarState.FULLSCREEN_USER_SWITCHER) { - mFullscreenUserSwitcher.show(); // Makes the switcher visible. - } - } - - private void hideUserSwitcher() { - if (mFullscreenUserSwitcher != null) { - mFullscreenUserSwitcher.hide(); - } - } - final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { @Override public void onScreenTurnedOn() { @@ -1024,7 +1002,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt // We automatically dismiss keyguard unless user switcher is being shown on the keyguard. private void dismissKeyguardWhenUserSwitcherNotDisplayed() { - if (mFullscreenUserSwitcher == null) { + if (!mUserSwitcherController.useFullscreenUserSwitcher()) { return; // Not using the full screen user switcher. } diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java index 0ad0992b68a4..2a2eb6976653 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java @@ -24,6 +24,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.R; import com.android.systemui.dock.DockManager; +import com.android.systemui.navigationbar.car.CarNavigationBarController; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.phone.NavigationModeController; @@ -40,6 +41,8 @@ import javax.inject.Singleton; public class CarStatusBarKeyguardViewManager extends StatusBarKeyguardViewManager { protected boolean mShouldHideNavBar; + private final CarNavigationBarController mCarNavigationBarController; + private final FullscreenUserSwitcher mFullscreenUserSwitcher; @Inject public CarStatusBarKeyguardViewManager(Context context, @@ -52,13 +55,17 @@ public class CarStatusBarKeyguardViewManager extends StatusBarKeyguardViewManage DockManager dockManager, StatusBarWindowController statusBarWindowController, KeyguardStateController keyguardStateController, - NotificationMediaManager notificationMediaManager) { + NotificationMediaManager notificationMediaManager, + CarNavigationBarController carNavigationBarController, + FullscreenUserSwitcher fullscreenUserSwitcher) { super(context, callback, lockPatternUtils, sysuiStatusBarStateController, configurationController, keyguardUpdateMonitor, navigationModeController, dockManager, statusBarWindowController, keyguardStateController, notificationMediaManager); mShouldHideNavBar = context.getResources() .getBoolean(R.bool.config_hideNavWhenKeyguardBouncerShown); + mCarNavigationBarController = carNavigationBarController; + mFullscreenUserSwitcher = fullscreenUserSwitcher; } @Override @@ -66,8 +73,10 @@ public class CarStatusBarKeyguardViewManager extends StatusBarKeyguardViewManage if (!mShouldHideNavBar) { return; } - CarStatusBar statusBar = (CarStatusBar) mStatusBar; - statusBar.setNavBarVisibility(navBarVisible ? View.VISIBLE : View.GONE); + int visibility = navBarVisible ? View.VISIBLE : View.GONE; + mCarNavigationBarController.setBottomWindowVisibility(visibility); + mCarNavigationBarController.setLeftWindowVisibility(visibility); + mCarNavigationBarController.setRightWindowVisibility(visibility); } /** @@ -86,8 +95,7 @@ public class CarStatusBarKeyguardViewManager extends StatusBarKeyguardViewManage */ @Override public void onCancelClicked() { - CarStatusBar statusBar = (CarStatusBar) mStatusBar; - statusBar.showUserSwitcher(); + mFullscreenUserSwitcher.show(); } /** diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java index e5a091f94077..3abbe32df2da 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java @@ -31,6 +31,7 @@ import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.car.CarServiceProvider; +import com.android.systemui.car.SystemUIPrimaryWindowController; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.keyguard.DismissCallbackRegistry; @@ -66,8 +67,8 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl; -import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; +import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.phone.AutoHideController; @@ -138,7 +139,7 @@ public class CarStatusBarModule { HeadsUpManagerPhone headsUpManagerPhone, DynamicPrivacyController dynamicPrivacyController, BypassHeadsUpNotifier bypassHeadsUpNotifier, - Lazy<NewNotifPipeline> newNotifPipeline, + Lazy<NotifPipelineInitializer> notifPipelineInitializer, FalsingManager falsingManager, BroadcastDispatcher broadcastDispatcher, RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, @@ -207,7 +208,8 @@ public class CarStatusBarModule { DismissCallbackRegistry dismissCallbackRegistry, CarServiceProvider carServiceProvider, Lazy<PowerManagerHelper> powerManagerHelperLazy, - Lazy<FullscreenUserSwitcher> fullscreenUserSwitcherLazy, + FullscreenUserSwitcher fullscreenUserSwitcher, + SystemUIPrimaryWindowController systemUIPrimaryWindowController, CarNavigationBarController carNavigationBarController, FlingAnimationUtils.Builder flingAnimationUtilsBuilder) { return new CarStatusBar( @@ -224,7 +226,7 @@ public class CarStatusBarModule { headsUpManagerPhone, dynamicPrivacyController, bypassHeadsUpNotifier, - newNotifPipeline, + notifPipelineInitializer, falsingManager, broadcastDispatcher, remoteInputQuickSettingsDisabler, @@ -292,7 +294,8 @@ public class CarStatusBarModule { dismissCallbackRegistry, carServiceProvider, powerManagerHelperLazy, - fullscreenUserSwitcherLazy, + fullscreenUserSwitcher, + systemUIPrimaryWindowController, carNavigationBarController, flingAnimationUtilsBuilder); } diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java index f8fc3bbefb01..3cd66c232717 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java @@ -38,6 +38,7 @@ import androidx.recyclerview.widget.GridLayoutManager; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.R; import com.android.systemui.car.CarServiceProvider; +import com.android.systemui.car.SystemUIPrimaryWindowController; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.statusbar.car.CarTrustAgentUnlockDialogHelper.OnHideListener; import com.android.systemui.statusbar.car.UserGridRecyclerView.UserRecord; @@ -56,9 +57,10 @@ public class FullscreenUserSwitcher { private final UserManager mUserManager; private final CarServiceProvider mCarServiceProvider; private final CarTrustAgentUnlockDialogHelper mUnlockDialogHelper; + private final SystemUIPrimaryWindowController mSystemUIPrimaryWindowController; + private CarStatusBar mCarStatusBar; private final int mShortAnimDuration; - private CarStatusBar mStatusBar; private View mParent; private UserGridRecyclerView mUserGridView; private CarTrustAgentEnrollmentManager mEnrollmentManager; @@ -81,23 +83,35 @@ public class FullscreenUserSwitcher { @Main Resources resources, UserManager userManager, CarServiceProvider carServiceProvider, - CarTrustAgentUnlockDialogHelper carTrustAgentUnlockDialogHelper) { + CarTrustAgentUnlockDialogHelper carTrustAgentUnlockDialogHelper, + SystemUIPrimaryWindowController systemUIPrimaryWindowController) { mContext = context; mResources = resources; mUserManager = userManager; mCarServiceProvider = carServiceProvider; mUnlockDialogHelper = carTrustAgentUnlockDialogHelper; + mSystemUIPrimaryWindowController = systemUIPrimaryWindowController; mShortAnimDuration = mResources.getInteger(android.R.integer.config_shortAnimTime); } - /** Sets the status bar which controls the keyguard. */ + /** Sets the status bar which gives an entry point to dismiss the keyguard. */ + // TODO: Remove this in favor of a keyguard controller. public void setStatusBar(CarStatusBar statusBar) { - mStatusBar = statusBar; + mCarStatusBar = statusBar; + } + + /** Returns {@code true} if the user switcher already has a parent view. */ + public boolean isAttached() { + return mParent != null; } /** Sets the {@link ViewStub} to show the user switcher. */ public void setContainer(ViewStub containerStub) { + if (isAttached()) { + return; + } + mParent = containerStub.inflate(); View container = mParent.findViewById(R.id.container); @@ -148,20 +162,31 @@ public class FullscreenUserSwitcher { * Makes user grid visible. */ public void show() { + if (!isAttached()) { + return; + } mParent.setVisibility(View.VISIBLE); + mSystemUIPrimaryWindowController.setWindowExpanded(true); } /** * Hides the user grid. */ public void hide() { + if (!isAttached()) { + return; + } mParent.setVisibility(View.INVISIBLE); + mSystemUIPrimaryWindowController.setWindowExpanded(false); } /** * @return {@code true} if user grid is visible, {@code false} otherwise. */ public boolean isVisible() { + if (!isAttached()) { + return false; + } return mParent.getVisibility() == View.VISIBLE; } @@ -196,7 +221,7 @@ public class FullscreenUserSwitcher { } if (mSelectedUser.mType == UserRecord.FOREGROUND_USER) { hide(); - mStatusBar.dismissKeyguard(); + mCarStatusBar.dismissKeyguard(); return; } // Switching is about to happen, since it takes time, fade out the switcher gradually. diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java index cdabeebe2819..8c756ecbaefc 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java @@ -43,6 +43,9 @@ import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowInsets; +import android.view.WindowManager; import android.widget.ImageView; import android.widget.TextView; @@ -53,7 +56,6 @@ import androidx.recyclerview.widget.RecyclerView; import com.android.internal.util.UserIcons; import com.android.systemui.R; -import com.android.systemui.statusbar.phone.SystemUIDialog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -337,7 +339,7 @@ public class UserGridRecyclerView extends RecyclerView { .setPositiveButton(android.R.string.ok, null) .create(); // Sets window flags for the SysUI dialog - SystemUIDialog.applyFlags(maxUsersDialog); + applyCarSysUIDialogFlags(maxUsersDialog); maxUsersDialog.show(); } @@ -356,10 +358,19 @@ public class UserGridRecyclerView extends RecyclerView { .setOnCancelListener(this) .create(); // Sets window flags for the SysUI dialog - SystemUIDialog.applyFlags(addUserDialog); + applyCarSysUIDialogFlags(addUserDialog); addUserDialog.show(); } + private void applyCarSysUIDialogFlags(AlertDialog dialog) { + final Window window = dialog.getWindow(); + window.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL); + window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM + | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); + window.setFitWindowInsetsTypes( + window.getFitWindowInsetsTypes() & ~WindowInsets.Type.statusBars()); + } + private void notifyUserSelected(UserRecord userRecord) { // Notify the listener which user was selected if (mUserSelectionListener != null) { diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java index 2697a1066ed2..cb062a63541e 100644 --- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java +++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java @@ -30,8 +30,6 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; -import com.android.internal.telephony.PhoneConstants; - /** * This util class provides common logic for carrier actions */ @@ -103,7 +101,7 @@ public class CarrierActionUtils { } private static void onDisableAllMeteredApns(Intent intent, Context context) { - int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, + int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SubscriptionManager.getDefaultVoiceSubscriptionId()); logd("onDisableAllMeteredApns subId: " + subId); final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class); @@ -111,7 +109,7 @@ public class CarrierActionUtils { } private static void onEnableAllMeteredApns(Intent intent, Context context) { - int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, + int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SubscriptionManager.getDefaultVoiceSubscriptionId()); logd("onEnableAllMeteredApns subId: " + subId); final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class); @@ -135,7 +133,7 @@ public class CarrierActionUtils { } private static void onRegisterDefaultNetworkAvail(Intent intent, Context context) { - int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, + int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SubscriptionManager.getDefaultVoiceSubscriptionId()); logd("onRegisterDefaultNetworkAvail subId: " + subId); final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class); @@ -143,7 +141,7 @@ public class CarrierActionUtils { } private static void onDeregisterDefaultNetworkAvail(Intent intent, Context context) { - int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, + int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SubscriptionManager.getDefaultVoiceSubscriptionId()); logd("onDeregisterDefaultNetworkAvail subId: " + subId); final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class); @@ -151,7 +149,7 @@ public class CarrierActionUtils { } private static void onDisableRadio(Intent intent, Context context) { - int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, + int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SubscriptionManager.getDefaultVoiceSubscriptionId()); logd("onDisableRadio subId: " + subId); final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class); @@ -159,7 +157,7 @@ public class CarrierActionUtils { } private static void onEnableRadio(Intent intent, Context context) { - int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, + int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SubscriptionManager.getDefaultVoiceSubscriptionId()); logd("onEnableRadio subId: " + subId); final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class); @@ -202,7 +200,7 @@ public class CarrierActionUtils { } private static void onResetAllCarrierActions(Intent intent, Context context) { - int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, + int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SubscriptionManager.getDefaultVoiceSubscriptionId()); logd("onResetAllCarrierActions subId: " + subId); final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class); diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java index 086a287fd243..6229434d1d86 100644 --- a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java +++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java @@ -15,6 +15,7 @@ */ package com.android.carrierdefaultapp; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; @@ -26,11 +27,10 @@ import android.app.PendingIntent; import android.content.Intent; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.test.InstrumentationTestCase; -import com.android.internal.telephony.PhoneConstants; - import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -69,6 +69,7 @@ public class CarrierDefaultReceiverTest extends InstrumentationTestCase { mContext.injectSystemService(NotificationManager.class, mNotificationMgr); mContext.injectSystemService(TelephonyManager.class, mTelephonyMgr); mContext.injectSystemService(CarrierConfigManager.class, mCarrierConfigMgr); + doReturn(mTelephonyMgr).when(mTelephonyMgr).createForSubscriptionId(anyInt()); mReceiver = new CarrierDefaultBroadcastReceiver(); } @@ -88,7 +89,7 @@ public class CarrierDefaultReceiverTest extends InstrumentationTestCase { doReturn(b).when(mCarrierConfigMgr).getConfig(); Intent intent = new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_REDIRECTED); - intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); + intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); mReceiver.onReceive(mContext, intent); mContext.waitForMs(100); diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index 81739e069e28..9d4c24e8faa4 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -211,13 +211,6 @@ public class AccessPoint implements Comparable<AccessPoint> { private static final int EAP_WPA = 1; // WPA-EAP private static final int EAP_WPA2_WPA3 = 2; // RSN-EAP - /** - * The number of distinct wifi levels. - * - * <p>Must keep in sync with {@link R.array.wifi_signal} and {@link WifiManager#RSSI_LEVELS}. - */ - public static final int SIGNAL_LEVELS = 5; - public static final int UNREACHABLE_RSSI = Integer.MIN_VALUE; public static final String KEY_PREFIX_AP = "AP:"; @@ -453,9 +446,10 @@ public class AccessPoint implements Comparable<AccessPoint> { return other.getSpeed() - getSpeed(); } + WifiManager wifiManager = getWifiManager(); // Sort by signal strength, bucketed by level - int difference = WifiManager.calculateSignalLevel(other.mRssi, SIGNAL_LEVELS) - - WifiManager.calculateSignalLevel(mRssi, SIGNAL_LEVELS); + int difference = wifiManager.calculateSignalLevel(other.mRssi) + - wifiManager.calculateSignalLevel(mRssi); if (difference != 0) { return difference; } @@ -869,13 +863,14 @@ public class AccessPoint implements Comparable<AccessPoint> { } /** - * Returns the number of levels to show for a Wifi icon, from 0 to {@link #SIGNAL_LEVELS}-1. + * Returns the number of levels to show for a Wifi icon, from 0 to + * {@link WifiManager#getMaxSignalLevel()}. * - * <p>Use {@#isReachable()} to determine if an AccessPoint is in range, as this method will + * <p>Use {@link #isReachable()} to determine if an AccessPoint is in range, as this method will * always return at least 0. */ public int getLevel() { - return WifiManager.calculateSignalLevel(mRssi, SIGNAL_LEVELS); + return getWifiManager().calculateSignalLevel(mRssi); } public int getRssi() { diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java b/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java index 4a4f0e66cfe8..f21e466dd8ab 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java @@ -22,6 +22,7 @@ import android.net.NetworkInfo; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.Parcelable; @@ -126,13 +127,15 @@ public class TestAccessPointBuilder { @Keep public TestAccessPointBuilder setLevel(int level) { // Reversal of WifiManager.calculateSignalLevels + WifiManager wifiManager = mContext.getSystemService(WifiManager.class); + int maxSignalLevel = wifiManager.getMaxSignalLevel(); if (level == 0) { mRssi = MIN_RSSI; - } else if (level >= AccessPoint.SIGNAL_LEVELS) { + } else if (level > maxSignalLevel) { mRssi = MAX_RSSI; } else { float inputRange = MAX_RSSI - MIN_RSSI; - float outputRange = AccessPoint.SIGNAL_LEVELS - 1; + float outputRange = maxSignalLevel; mRssi = (int) (level * inputRange / outputRange + MIN_RSSI); } return this; diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java index 8591116fce0f..3f55ceaad29a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java @@ -89,7 +89,7 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback { public void setListening(boolean listening) { if (listening) { mNetworkScoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, - mWifiNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK); + mWifiNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_CURRENT_NETWORK); mWifiNetworkScoreCache.registerListener(mCacheListener); mConnectivityManager.registerNetworkCallback( mNetworkRequest, mNetworkCallback, mHandler); diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index ba6a8ea31987..ed4ff085aeac 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -361,7 +361,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro mNetworkScoreManager.registerNetworkScoreCache( NetworkKey.TYPE_WIFI, mScoreCache, - NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS); + NetworkScoreManager.SCORE_FILTER_SCAN_RESULTS); } private void requestScoresForNetworkKeys(Collection<NetworkKey> keys) { diff --git a/packages/SettingsLib/tests/integ/Android.bp b/packages/SettingsLib/tests/integ/Android.bp index 4600793729a2..2ccff1ecaf6c 100644 --- a/packages/SettingsLib/tests/integ/Android.bp +++ b/packages/SettingsLib/tests/integ/Android.bp @@ -14,7 +14,10 @@ android_test { name: "SettingsLibTests", - defaults: ["SettingsLibDefaults"], + defaults: [ + "SettingsLibDefaults", + "framework-wifi-test-defaults" + ], certificate: "platform", diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java index 61cbbd3eb0a4..03201ae6d5ba 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java @@ -83,7 +83,6 @@ import java.util.concurrent.CountDownLatch; @SmallTest @RunWith(AndroidJUnit4.class) public class AccessPointTest { - private static final String TEST_SSID = "\"test_ssid\""; private static final String ROAMING_SSID = "\"roaming_ssid\""; private static final String OSU_FRIENDLY_NAME = "osu_friendly_name"; @@ -98,6 +97,7 @@ public class AccessPointTest { 20 * DateUtils.MINUTE_IN_MILLIS; private Context mContext; + private int mMaxSignalLevel; private WifiInfo mWifiInfo; @Mock private Context mMockContext; @Mock private WifiManager mMockWifiManager; @@ -128,6 +128,7 @@ public class AccessPointTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = InstrumentationRegistry.getTargetContext(); + mMaxSignalLevel = mContext.getSystemService(WifiManager.class).getMaxSignalLevel(); mWifiInfo = new WifiInfo(); mWifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(TEST_SSID)); mWifiInfo.setBSSID(TEST_BSSID); @@ -180,7 +181,7 @@ public class AccessPointTest { @Test public void testCompareTo_GivesHighLevelBeforeLowLevel() { - final int highLevel = AccessPoint.SIGNAL_LEVELS - 1; + final int highLevel = mMaxSignalLevel; final int lowLevel = 1; assertThat(highLevel).isGreaterThan(lowLevel); @@ -226,7 +227,7 @@ public class AccessPointTest { .setReachable(true).build(); AccessPoint saved = new TestAccessPointBuilder(mContext).setSaved(true).build(); AccessPoint highLevelAndReachable = new TestAccessPointBuilder(mContext) - .setLevel(AccessPoint.SIGNAL_LEVELS - 1).build(); + .setLevel(mMaxSignalLevel).build(); AccessPoint firstName = new TestAccessPointBuilder(mContext).setSsid("a").build(); AccessPoint lastname = new TestAccessPointBuilder(mContext).setSsid("z").build(); @@ -520,6 +521,8 @@ public class AccessPointTest { when(packageManager.getApplicationInfoAsUser(eq(appPackageName), anyInt(), anyInt())) .thenReturn(applicationInfo); when(applicationInfo.loadLabel(packageManager)).thenReturn(appLabel); + when(context.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager); + when(mMockWifiManager.calculateSignalLevel(rssi)).thenReturn(4); NetworkInfo networkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", ""); @@ -636,14 +639,14 @@ public class AccessPointTest { public void testBuilder_setLevel() { AccessPoint testAp; - for (int i = 0; i < AccessPoint.SIGNAL_LEVELS; i++) { + for (int i = 0; i <= mMaxSignalLevel; i++) { testAp = new TestAccessPointBuilder(mContext).setLevel(i).build(); assertThat(testAp.getLevel()).isEqualTo(i); } // numbers larger than the max level should be set to max - testAp = new TestAccessPointBuilder(mContext).setLevel(AccessPoint.SIGNAL_LEVELS).build(); - assertThat(testAp.getLevel()).isEqualTo(AccessPoint.SIGNAL_LEVELS - 1); + testAp = new TestAccessPointBuilder(mContext).setLevel(mMaxSignalLevel + 1).build(); + assertThat(testAp.getLevel()).isEqualTo(mMaxSignalLevel); // numbers less than 0 should give level 0 testAp = new TestAccessPointBuilder(mContext).setLevel(-100).build(); @@ -653,7 +656,7 @@ public class AccessPointTest { @Test public void testBuilder_settingReachableAfterLevelDoesNotAffectLevel() { int level = 1; - assertThat(level).isLessThan(AccessPoint.SIGNAL_LEVELS - 1); + assertThat(level).isLessThan(mMaxSignalLevel); AccessPoint testAp = new TestAccessPointBuilder(mContext).setLevel(level).setReachable(true).build(); diff --git a/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml new file mode 100644 index 000000000000..50aa212c94a6 --- /dev/null +++ b/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2008 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. +--> + +<!-- RelativeLayouts have an issue enforcing minimum heights, so just + work around this for now with LinearLayouts. --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center" + android:paddingTop="@dimen/global_actions_grid_item_vertical_margin" + android:paddingBottom="@dimen/global_actions_grid_item_vertical_margin" + android:paddingLeft="@dimen/global_actions_grid_item_side_margin" + android:paddingRight="@dimen/global_actions_grid_item_side_margin" + android:layout_marginRight="3dp" + android:layout_marginLeft="3dp" + android:background="@drawable/rounded_bg_full"> + <LinearLayout + android:layout_width="@dimen/global_actions_grid_item_width" + android:layout_height="@dimen/global_actions_grid_item_height" + android:gravity="top|center_horizontal" + android:orientation="vertical"> + <ImageView + android:id="@*android:id/icon" + android:layout_width="@dimen/global_actions_grid_item_icon_width" + android:layout_height="@dimen/global_actions_grid_item_icon_height" + android:layout_marginTop="@dimen/global_actions_grid_item_icon_top_margin" + android:layout_marginBottom="@dimen/global_actions_grid_item_icon_bottom_margin" + android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin" + android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin" + android:scaleType="centerInside" + android:tint="@color/global_actions_text" /> + + <TextView + android:id="@*android:id/message" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ellipsize="marquee" + android:marqueeRepeatLimit="marquee_forever" + android:singleLine="true" + android:gravity="center" + android:textSize="12dp" + android:textColor="@color/global_actions_text" + android:textAppearance="?android:attr/textAppearanceSmall" /> + + <TextView + android:visibility="gone" + android:id="@*android:id/status" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:textColor="@color/global_actions_text" + android:textAppearance="?android:attr/textAppearanceSmall" /> + </LinearLayout> +</LinearLayout> diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml new file mode 100644 index 000000000000..4cfb47e3c642 --- /dev/null +++ b/packages/SystemUI/res/layout/global_actions_grid_v2.xml @@ -0,0 +1,130 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/global_actions_grid_root" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clipChildren="false" + android:clipToPadding="false" + android:layout_marginBottom="@dimen/global_actions_grid_container_negative_shadow_offset"> + + <com.android.systemui.globalactions.GlobalActionsFlatLayout + android:id="@id/global_actions_view" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:theme="@style/qs_theme" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + android:gravity="top | center_horizontal" + android:clipChildren="false" + android:clipToPadding="false" + android:paddingBottom="@dimen/global_actions_grid_container_shadow_offset" + android:layout_marginTop="@dimen/global_actions_top_margin" + android:layout_marginBottom="@dimen/global_actions_grid_container_negative_shadow_offset"> + <LinearLayout + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layoutDirection="ltr" + android:clipChildren="false" + android:clipToPadding="false" + android:layout_marginBottom="@dimen/global_actions_grid_container_bottom_margin"> + <!-- For separated items--> + <LinearLayout + android:id="@+id/separated_button" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_marginLeft="@dimen/global_actions_grid_side_margin" + android:layout_marginRight="@dimen/global_actions_grid_side_margin" + android:paddingLeft="@dimen/global_actions_grid_horizontal_padding" + android:paddingRight="@dimen/global_actions_grid_horizontal_padding" + android:paddingTop="@dimen/global_actions_grid_vertical_padding" + android:paddingBottom="@dimen/global_actions_grid_vertical_padding" + android:orientation="vertical" + android:gravity="center" + android:translationZ="@dimen/global_actions_translate" + /> + <!-- Grid of action items --> + <com.android.systemui.globalactions.ListGridLayout + android:id="@android:id/list" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + android:gravity="right" + android:layout_marginRight="@dimen/global_actions_grid_side_margin" + android:translationZ="@dimen/global_actions_translate" + android:paddingLeft="@dimen/global_actions_grid_horizontal_padding" + android:paddingRight="@dimen/global_actions_grid_horizontal_padding" + android:paddingTop="@dimen/global_actions_grid_vertical_padding" + android:paddingBottom="@dimen/global_actions_grid_vertical_padding" + > + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:visibility="gone" + android:layoutDirection="locale" + /> + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:visibility="gone" + android:layoutDirection="locale" + /> + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:visibility="gone" + android:layoutDirection="locale" + /> + </com.android.systemui.globalactions.ListGridLayout> + </LinearLayout> + </com.android.systemui.globalactions.GlobalActionsFlatLayout> + + <LinearLayout + android:id="@+id/global_actions_panel" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toBottomOf="@id/global_actions_view"> + + <FrameLayout + android:translationY="@dimen/global_actions_plugin_offset" + android:id="@+id/global_actions_panel_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + </LinearLayout> + + <LinearLayout + android:translationY="@dimen/global_actions_plugin_offset" + android:id="@+id/global_actions_controls" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toBottomOf="@id/global_actions_panel"> + <TextView + android:text="Home" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:singleLine="true" + android:gravity="center" + android:textSize="25dp" + android:textColor="?android:attr/textColorPrimary" + android:fontFamily="@*android:string/config_headlineFontFamily" /> + <LinearLayout + android:id="@+id/global_actions_controls_list" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" /> + </LinearLayout> + </androidx.constraintlayout.widget.ConstraintLayout> +</ScrollView> diff --git a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml index 6b424002d7ff..366abaa1366d 100644 --- a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml +++ b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml @@ -14,12 +14,27 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<TextView xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/global_screenshot_action_chip" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginHorizontal="@dimen/screenshot_action_chip_margin_horizontal" - android:paddingVertical="@dimen/screenshot_action_chip_padding_vertical" - android:paddingHorizontal="@dimen/screenshot_action_chip_padding_horizontal" - android:background="@drawable/action_chip_background" - android:textColor="@color/global_screenshot_button_text"/> +<com.android.systemui.screenshot.ScreenshotActionChip + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/global_screenshot_action_chip" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/screenshot_action_chip_margin_horizontal" + android:layout_gravity="center" + android:paddingVertical="@dimen/screenshot_action_chip_padding_vertical" + android:background="@drawable/action_chip_background" + android:gravity="center"> + <ImageView + android:id="@+id/screenshot_action_chip_icon" + android:layout_width="@dimen/screenshot_action_chip_icon_size" + android:layout_height="@dimen/screenshot_action_chip_icon_size" + android:layout_marginStart="@dimen/screenshot_action_chip_padding_start" + android:layout_marginEnd="@dimen/screenshot_action_chip_padding_middle"/> + <TextView + android:id="@+id/screenshot_action_chip_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/screenshot_action_chip_padding_end" + android:textSize="@dimen/screenshot_action_chip_text_size" + android:textColor="@color/global_screenshot_button_text"/> +</com.android.systemui.screenshot.ScreenshotActionChip> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 5a1151eb9f6e..c26cb9a18dd4 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -291,12 +291,17 @@ <dimen name="global_screenshot_legacy_bg_padding">20dp</dimen> <dimen name="global_screenshot_bg_padding">20dp</dimen> <dimen name="screenshot_action_container_corner_radius">10dp</dimen> - <dimen name="screenshot_action_container_padding">20dp</dimen> + <dimen name="screenshot_action_container_padding">10dp</dimen> <!-- Radius of the chip background on global screenshot actions --> <dimen name="screenshot_button_corner_radius">20dp</dimen> - <dimen name="screenshot_action_chip_margin_horizontal">10dp</dimen> + <dimen name="screenshot_action_chip_margin_horizontal">4dp</dimen> <dimen name="screenshot_action_chip_padding_vertical">10dp</dimen> - <dimen name="screenshot_action_chip_padding_horizontal">15dp</dimen> + <dimen name="screenshot_action_chip_icon_size">20dp</dimen> + <dimen name="screenshot_action_chip_padding_start">4dp</dimen> + <!-- Padding between icon and text --> + <dimen name="screenshot_action_chip_padding_middle">8dp</dimen> + <dimen name="screenshot_action_chip_padding_end">12dp</dimen> + <dimen name="screenshot_action_chip_text_size">14sp</dimen> <!-- The width of the view containing navigation buttons --> @@ -951,6 +956,9 @@ <dimen name="cell_overlay_padding">18dp</dimen> <!-- Global actions power menu --> + <dimen name="global_actions_top_margin">12dp</dimen> + <dimen name="global_actions_plugin_offset">-145dp</dimen> + <dimen name="global_actions_panel_width">120dp</dimen> <dimen name="global_actions_padding">12dp</dimen> <dimen name="global_actions_translate">9dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java index 8105faa23e89..eab970626bf1 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java @@ -27,9 +27,9 @@ import android.util.Log; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.collection.NotifCollection; -import com.android.systemui.statusbar.notification.collection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import javax.inject.Inject; import javax.inject.Singleton; @@ -49,7 +49,7 @@ public class ForegroundServiceNotificationListener { public ForegroundServiceNotificationListener(Context context, ForegroundServiceController foregroundServiceController, NotificationEntryManager notificationEntryManager, - NotifCollection notifCollection) { + NotifPipeline notifPipeline) { mContext = context; mForegroundServiceController = foregroundServiceController; @@ -77,7 +77,7 @@ public class ForegroundServiceNotificationListener { }); mEntryManager.addNotificationLifetimeExtender(new ForegroundServiceLifetimeExtender()); - notifCollection.addCollectionListener(new NotifCollectionListener() { + notifPipeline.addCollectionListener(new NotifCollectionListener() { @Override public void onEntryAdded(NotificationEntry entry) { addNotification(entry, entry.getImportance()); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java index 563a0a7e43e1..31656a00c3ed 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java @@ -961,6 +961,13 @@ public class PhysicsAnimationLayout extends FrameLayout { if (view != null) { final SpringAnimation animation = (SpringAnimation) view.getTag(getTagIdForProperty(property)); + + // If the animation is null, the view was probably removed from the layout before + // the animation started. + if (animation == null) { + return; + } + if (afterCallbacks != null) { animation.addEndListener(new OneTimeEndListener() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index b19523866814..a6fa4146300d 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -30,10 +30,8 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.Recents; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl; -import com.android.systemui.statusbar.notification.collection.NotificationRowBinder; -import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl; -import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; import com.android.systemui.statusbar.notification.people.PeopleHubModule; import com.android.systemui.statusbar.phone.KeyguardLiftController; import com.android.systemui.statusbar.phone.StatusBar; @@ -113,9 +111,4 @@ public abstract class SystemUIModule { @Singleton @Binds abstract SystemClock bindSystemClock(SystemClockImpl systemClock); - - @Singleton - @Binds - abstract NotifListBuilder bindNotifListBuilder(NotifListBuilderImpl impl); - } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 91bb80c60e3f..c138462d06c4 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -59,7 +59,6 @@ import android.telecom.TelecomManager; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.TelephonyManager; -import android.text.TextUtils; import android.util.ArraySet; import android.util.FeatureFlagUtils; import android.util.Log; @@ -444,7 +443,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mKeyguardManager.isDeviceLocked()) : null; - ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, panelViewController); + ActionsDialog dialog = new ActionsDialog( + mContext, mAdapter, panelViewController, isControlsEnabled(mContext)); dialog.setCanceledOnTouchOutside(false); // Handled by the custom class. dialog.setKeyguardShowing(mKeyguardShowing); @@ -518,7 +518,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, @Override public boolean shouldBeSeparated() { - return shouldUseSeparatedView(); + return !isControlsEnabled(mContext); } @Override @@ -1154,6 +1154,9 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } protected int getActionLayoutId(Context context) { + if (isControlsEnabled(context)) { + return com.android.systemui.R.layout.global_actions_grid_item_v2; + } return com.android.systemui.R.layout.global_actions_grid_item; } @@ -1415,8 +1418,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } else if (TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) { // Airplane mode can be changed after ECM exits if airplane toggle button // is pressed during ECM mode - if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) && - mIsWaitingForEcmExit) { + if (!(intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)) + && mIsWaitingForEcmExit) { mIsWaitingForEcmExit = false; changeAirplaneModeSystemSetting(true); } @@ -1526,15 +1529,18 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private ResetOrientationData mResetOrientationData; private boolean mHadTopUi; private final StatusBarWindowController mStatusBarWindowController; + private boolean mControlsEnabled; ActionsDialog(Context context, MyAdapter adapter, - GlobalActionsPanelPlugin.PanelViewController plugin) { + GlobalActionsPanelPlugin.PanelViewController plugin, + boolean controlsEnabled) { super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions); mContext = context; mAdapter = adapter; mColorExtractor = Dependency.get(SysuiColorExtractor.class); mStatusBarService = Dependency.get(IStatusBarService.class); mStatusBarWindowController = Dependency.get(StatusBarWindowController.class); + mControlsEnabled = controlsEnabled; // Window initialization Window window = getWindow(); @@ -1651,6 +1657,10 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } private int getGlobalActionsLayoutId(Context context) { + if (mControlsEnabled) { + return com.android.systemui.R.layout.global_actions_grid_v2; + } + int rotation = RotationUtils.getRotation(context); boolean useGridLayout = isForceGridEnabled(context) || (shouldUsePanel() && rotation == RotationUtils.ROTATION_NONE); @@ -1854,4 +1864,9 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private static boolean shouldUseSeparatedView() { return true; } + + private static boolean isControlsEnabled(Context context) { + return Settings.Secure.getInt( + context.getContentResolver(), "systemui.controls_available", 0) == 1; + } } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java new file mode 100644 index 000000000000..6749f1d663eb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2019 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.globalactions; + +import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE; +import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE; +import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * Single row implementation of the button layout created by the global actions dialog. + */ +public class GlobalActionsFlatLayout extends GlobalActionsLayout { + public GlobalActionsFlatLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + mBackgroundsSet = true; + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + // backgrounds set only once, the first time onMeasure is called after inflation + // if (getListView() != null && !mBackgroundsSet) { + // setBackgrounds(); + // mBackgroundsSet = true; + // } + } + + @VisibleForTesting + protected void setupListView() { + ListGridLayout listView = getListView(); + listView.setExpectedCount(Math.min(2, mAdapter.countListItems())); + listView.setReverseSublists(shouldReverseSublists()); + listView.setReverseItems(shouldReverseListItems()); + listView.setSwapRowsAndColumns(shouldSwapRowsAndColumns()); + } + + @Override + public void onUpdateList() { + setupListView(); + super.onUpdateList(); + updateSeparatedItemSize(); + } + + /** + * If the separated view contains only one item, expand the bounds of that item to take up the + * entire view, so that the whole thing is touch-able. + */ + @VisibleForTesting + protected void updateSeparatedItemSize() { + ViewGroup separated = getSeparatedView(); + if (separated.getChildCount() == 0) { + return; + } + View firstChild = separated.getChildAt(0); + ViewGroup.LayoutParams childParams = firstChild.getLayoutParams(); + + if (separated.getChildCount() == 1) { + childParams.width = ViewGroup.LayoutParams.MATCH_PARENT; + childParams.height = ViewGroup.LayoutParams.MATCH_PARENT; + } else { + childParams.width = ViewGroup.LayoutParams.WRAP_CONTENT; + childParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; + } + } + + @Override + protected ListGridLayout getListView() { + return (ListGridLayout) super.getListView(); + } + + @Override + protected void removeAllListViews() { + ListGridLayout list = getListView(); + if (list != null) { + list.removeAllItems(); + } + } + + @Override + protected void addToListView(View v, boolean reverse) { + ListGridLayout list = getListView(); + if (list != null) { + list.addItem(v); + } + } + + @Override + public void removeAllItems() { + ViewGroup separatedList = getSeparatedView(); + ListGridLayout list = getListView(); + if (separatedList != null) { + separatedList.removeAllViews(); + } + if (list != null) { + list.removeAllItems(); + } + } + + /** + * Determines whether the ListGridLayout should fill sublists in the reverse order. + * Used to account for sublist ordering changing between landscape and seascape views. + */ + @VisibleForTesting + protected boolean shouldReverseSublists() { + if (getCurrentRotation() == ROTATION_SEASCAPE) { + return true; + } + return false; + } + + /** + * Determines whether the ListGridLayout should fill rows first instead of columns. + * Used to account for vertical/horizontal changes due to landscape or seascape rotations. + */ + @VisibleForTesting + protected boolean shouldSwapRowsAndColumns() { + if (getCurrentRotation() == ROTATION_NONE) { + return false; + } + return true; + } + + @Override + protected boolean shouldReverseListItems() { + int rotation = getCurrentRotation(); + boolean reverse = false; // should we add items to parents in the reverse order? + if (rotation == ROTATION_NONE + || rotation == ROTATION_SEASCAPE) { + reverse = !reverse; // if we're in portrait or seascape, reverse items + } + if (getCurrentLayoutDirection() == View.LAYOUT_DIRECTION_RTL) { + reverse = !reverse; // if we're in an RTL language, reverse items (again) + } + return reverse; + } + + @VisibleForTesting + protected float getAnimationDistance() { + int rows = getListView().getRowCount(); + float gridItemSize = getContext().getResources().getDimension( + com.android.systemui.R.dimen.global_actions_grid_item_height); + return rows * gridItemSize / 2; + } + + @Override + public float getAnimationOffsetX() { + switch (getCurrentRotation()) { + case ROTATION_LANDSCAPE: + return getAnimationDistance(); + case ROTATION_SEASCAPE: + return -getAnimationDistance(); + default: // Portrait + return 0; + } + } + + @Override + public float getAnimationOffsetY() { + if (getCurrentRotation() == ROTATION_NONE) { + return getAnimationDistance(); + } + return 0; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index 9f2bbc680897..27c95552c1d1 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -64,7 +64,6 @@ import android.view.WindowManager; import android.view.animation.Interpolator; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.TextView; import android.widget.Toast; import com.android.systemui.R; @@ -529,9 +528,10 @@ public class GlobalScreenshot { mActionsView.removeAllViews(); for (Notification.Action action : actions) { - TextView actionChip = (TextView) inflater.inflate( + ScreenshotActionChip actionChip = (ScreenshotActionChip) inflater.inflate( R.layout.global_screenshot_action_chip, mActionsView, false); actionChip.setText(action.title); + actionChip.setIcon(action.getIcon(), true); actionChip.setOnClickListener(v -> { try { action.actionIntent.send(); @@ -545,11 +545,11 @@ public class GlobalScreenshot { } if (DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, SCREENSHOT_SCROLLING_ENABLED, false)) { - TextView scrollChip = (TextView) inflater.inflate( + ScreenshotActionChip scrollChip = (ScreenshotActionChip) inflater.inflate( R.layout.global_screenshot_action_chip, mActionsView, false); Toast scrollNotImplemented = Toast.makeText( mContext, "Not implemented", Toast.LENGTH_SHORT); - scrollChip.setText("Scroll"); // TODO (mkephart): add resource and translate + scrollChip.setText("Extend"); // TODO (mkephart): add resource and translate scrollChip.setOnClickListener(v -> scrollNotImplemented.show()); mActionsView.addView(scrollChip); } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionChip.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionChip.java new file mode 100644 index 000000000000..6edacd12a9d1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionChip.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2020 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.screenshot; + +import android.annotation.ColorInt; +import android.content.Context; +import android.graphics.drawable.Icon; +import android.util.AttributeSet; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.android.systemui.R; + +/** + * View for a chip with an icon and text. + */ +public class ScreenshotActionChip extends LinearLayout { + + private ImageView mIcon; + private TextView mText; + private @ColorInt int mIconColor; + + public ScreenshotActionChip(Context context) { + this(context, null); + } + + public ScreenshotActionChip(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ScreenshotActionChip(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public ScreenshotActionChip(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + + mIconColor = context.getColor(R.color.global_screenshot_button_text); + } + + @Override + protected void onFinishInflate() { + mIcon = findViewById(R.id.screenshot_action_chip_icon); + mText = findViewById(R.id.screenshot_action_chip_text); + } + + void setIcon(Icon icon, boolean tint) { + if (tint) { + icon.setTint(mIconColor); + } + mIcon.setImageIcon(icon); + } + + void setText(CharSequence text) { + mText.setText(text); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index 36dcaac15a5f..4a2283171694 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -43,7 +43,7 @@ import com.android.systemui.statusbar.NotificationRemoveInterceptor; import com.android.systemui.statusbar.NotificationUiAdjustment; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; -import com.android.systemui.statusbar.notification.collection.NotificationRowBinder; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; import com.android.systemui.statusbar.notification.logging.NotifEvent; import com.android.systemui.statusbar.notification.logging.NotifLog; import com.android.systemui.statusbar.notification.logging.NotificationLogger; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java index e1268f6d60ef..73bfe2536830 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java @@ -16,13 +16,11 @@ package com.android.systemui.statusbar.notification.collection; -import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder; - import java.util.List; /** - * Utility class for dumping the results of a {@link NotifListBuilder} to a debug string. + * Utility class for dumping the results of a {@link ShadeListBuilder} to a debug string. */ public class ListDumper { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java index 856b75b7e36c..4b15b7fbce5d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java @@ -47,9 +47,13 @@ import android.util.ArrayMap; import android.util.Log; import com.android.internal.statusbar.IStatusBarService; -import com.android.systemui.statusbar.notification.collection.notifcollection.CoalescedEvent; -import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer; -import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer.BatchableNotificationHandler; +import com.android.systemui.statusbar.notification.collection.coalescer.CoalescedEvent; +import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer; +import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer.BatchableNotificationHandler; +import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener; +import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; import com.android.systemui.util.Assert; import java.lang.annotation.Retention; @@ -123,36 +127,25 @@ public class NotifCollection { * Sets the class responsible for converting the collection into the list of currently-visible * notifications. */ - public void setBuildListener(CollectionReadyForBuildListener buildListener) { + void setBuildListener(CollectionReadyForBuildListener buildListener) { Assert.isMainThread(); mBuildListener = buildListener; } - /** - * Returns the list of "active" notifications, i.e. the notifications that are currently posted - * to the phone. In general, this tracks closely to the list maintained by NotificationManager, - * but it can diverge slightly due to lifetime extenders. - * - * The returned list is read-only, unsorted, unfiltered, and ungrouped. - */ - public Collection<NotificationEntry> getNotifs() { + /** @see NotifPipeline#getActiveNotifs() */ + Collection<NotificationEntry> getActiveNotifs() { Assert.isMainThread(); return mReadOnlyNotificationSet; } - /** - * Registers a listener to be informed when notifications are added, removed or updated. - */ - public void addCollectionListener(NotifCollectionListener listener) { + /** @see NotifPipeline#addCollectionListener(NotifCollectionListener) */ + void addCollectionListener(NotifCollectionListener listener) { Assert.isMainThread(); mNotifCollectionListeners.add(listener); } - /** - * Registers a lifetime extender. Lifetime extenders can cause notifications that have been - * dismissed or retracted to be temporarily retained in the collection. - */ - public void addNotificationLifetimeExtender(NotifLifetimeExtender extender) { + /** @see NotifPipeline#addNotificationLifetimeExtender(NotifLifetimeExtender) */ + void addNotificationLifetimeExtender(NotifLifetimeExtender extender) { Assert.isMainThread(); checkForReentrantCall(); if (mLifetimeExtenders.contains(extender)) { @@ -165,7 +158,7 @@ public class NotifCollection { /** * Dismiss a notification on behalf of the user. */ - public void dismissNotification( + void dismissNotification( NotificationEntry entry, @CancellationReason int reason, @NonNull DismissedByUserStats stats) { @@ -446,7 +439,7 @@ public class NotifCollection { REASON_TIMEOUT, }) @Retention(RetentionPolicy.SOURCE) - @interface CancellationReason {} + public @interface CancellationReason {} public static final int REASON_UNKNOWN = 0; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java index 0d175574f16b..e7b772f1c7b2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java @@ -25,6 +25,9 @@ import android.service.notification.StatusBarNotification; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.statusbar.notification.InflationException; +import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; +import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationContentInflater; @@ -107,7 +110,7 @@ public class NotifInflaterImpl implements NotifInflater { DISMISS_SENTIMENT_NEUTRAL, NotificationVisibility.obtain(entry.getKey(), entry.getRanking().getRank(), - mNotifCollection.getNotifs().size(), + mNotifCollection.getActiveNotifs().size(), true, NotificationLogger.getNotificationLocation(entry)) )); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java new file mode 100644 index 000000000000..71245178a876 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.collection; + +import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener; +import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener; +import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener; +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator; +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.SectionsProvider; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; + +import java.util.Collection; +import java.util.List; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * The system that constructs the "shade list", the filtered, grouped, and sorted list of + * notifications that are currently being displayed to the user in the notification shade. + * + * The pipeline proceeds through a series of stages in order to produce the final list (see below). + * Each stage exposes hooks and listeners to allow other code to participate. + * + * This list differs from the canonical one we receive from system server in a few ways: + * - Filtered: Some notifications are filtered out. For example, we filter out notifications whose + * views haven't been inflated yet. We also filter out some notifications if we're on the lock + * screen and notifications for other users. So participate, see + * {@link #addPreGroupFilter} and similar methods. + * - Grouped: Notifications that are part of the same group are clustered together into a single + * GroupEntry. These groups are then transformed in order to remove children or completely split + * them apart. To participate, see {@link #addPromoter}. + * - Sorted: All top-level notifications are sorted. To participate, see + * {@link #setSectionsProvider} and {@link #setComparators} + * + * The exact order of all hooks is as follows: + * 0. Collection listeners are fired ({@link #addCollectionListener}). + * 1. Pre-group filters are fired on each notification ({@link #addPreGroupFilter}). + * 2. Initial grouping is performed (NotificationEntries will have their parents set + * appropriately). + * 3. OnBeforeTransformGroupListeners are fired ({@link #addOnBeforeTransformGroupsListener}) + * 4. NotifPromoters are called on each notification with a parent ({@link #addPromoter}) + * 5. OnBeforeSortListeners are fired ({@link #addOnBeforeSortListener}) + * 6. SectionsProvider is called on each top-level entry in the list ({@link #setSectionsProvider}) + * 7. Top-level entries within the same section are sorted by NotifComparators + * ({@link #setComparators}) + * 8. Pre-render filters are fired on each notification ({@link #addPreRenderFilter}) + * 9. OnBeforeRenderListListeners are fired ({@link #addOnBeforeRenderListListener}) + * 9. The list is handed off to the view layer to be rendered + */ +@Singleton +public class NotifPipeline { + private final NotifCollection mNotifCollection; + private final ShadeListBuilder mShadeListBuilder; + + @Inject + public NotifPipeline( + NotifCollection notifCollection, + ShadeListBuilder shadeListBuilder) { + mNotifCollection = notifCollection; + mShadeListBuilder = shadeListBuilder; + } + + /** + * Returns the list of "active" notifications, i.e. the notifications that are currently posted + * to the phone. In general, this tracks closely to the list maintained by NotificationManager, + * but it can diverge slightly due to lifetime extenders. + * + * The returned collection is read-only, unsorted, unfiltered, and ungrouped. + */ + public Collection<NotificationEntry> getActiveNotifs() { + return mNotifCollection.getActiveNotifs(); + } + + /** + * Registers a listener to be informed when notifications are added, removed or updated. + */ + public void addCollectionListener(NotifCollectionListener listener) { + mNotifCollection.addCollectionListener(listener); + } + + /** + * Registers a lifetime extender. Lifetime extenders can cause notifications that have been + * dismissed or retracted to be temporarily retained in the collection. + */ + public void addNotificationLifetimeExtender(NotifLifetimeExtender extender) { + mNotifCollection.addNotificationLifetimeExtender(extender); + } + + /** + * Registers a filter with the pipeline before grouping, promoting and sorting occurs. Filters + * are called on each notification in the order that they were registered. If any filter + * returns true, the notification is removed from the pipeline (and no other filters are + * called on that notif). + */ + public void addPreGroupFilter(NotifFilter filter) { + mShadeListBuilder.addPreGroupFilter(filter); + } + + /** + * Called after notifications have been filtered and after the initial grouping has been + * performed but before NotifPromoters have had a chance to promote children out of groups. + */ + public void addOnBeforeTransformGroupsListener(OnBeforeTransformGroupsListener listener) { + mShadeListBuilder.addOnBeforeTransformGroupsListener(listener); + } + + /** + * Registers a promoter with the pipeline. Promoters are able to promote child notifications to + * top-level, i.e. move a notification that would be a child of a group and make it appear + * ungrouped. Promoters are called on each child notification in the order that they are + * registered. If any promoter returns true, the notification is removed from the group (and no + * other promoters are called on it). + */ + public void addPromoter(NotifPromoter promoter) { + mShadeListBuilder.addPromoter(promoter); + } + + /** + * Called after notifs have been filtered and groups have been determined but before sections + * have been determined or the notifs have been sorted. + */ + public void addOnBeforeSortListener(OnBeforeSortListener listener) { + mShadeListBuilder.addOnBeforeSortListener(listener); + } + + /** + * Assigns sections to each top-level entry, where a section is simply an integer. Sections are + * the primary metric by which top-level entries are sorted; NotifComparators are only consulted + * when two entries are in the same section. The pipeline doesn't assign any particular meaning + * to section IDs -- from it's perspective they're just numbers and it sorts them by a simple + * numerical comparison. + */ + public void setSectionsProvider(SectionsProvider provider) { + mShadeListBuilder.setSectionsProvider(provider); + } + + /** + * Comparators that are used to sort top-level entries that share the same section. The + * comparators are executed in order until one of them returns a non-zero result. If all return + * zero, the pipeline falls back to sorting by rank (and, failing that, Notification.when). + */ + public void setComparators(List<NotifComparator> comparators) { + mShadeListBuilder.setComparators(comparators); + } + + /** + * Registers a filter with the pipeline to filter right before rendering the list (after + * pre-group filtering, grouping, promoting and sorting occurs). Filters are + * called on each notification in the order that they were registered. If any filter returns + * true, the notification is removed from the pipeline (and no other filters are called on that + * notif). + */ + public void addPreRenderFilter(NotifFilter filter) { + mShadeListBuilder.addPreRenderFilter(filter); + } + + /** + * Called at the end of the pipeline after the notif list has been finalized but before it has + * been handed off to the view layer. + */ + public void addOnBeforeRenderListListener(OnBeforeRenderListListener listener) { + mShadeListBuilder.addOnBeforeRenderListListener(listener); + } + + /** + * Returns a read-only view in to the current shade list, i.e. the list of notifications that + * are currently present in the shade. If this method is called during pipeline execution it + * will return the current state of the list, which will likely be only partially-generated. + */ + public List<ListEntry> getShadeList() { + return mShadeListBuilder.getShadeList(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index 7301fe1df398..2fcfb8c811aa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -59,6 +59,7 @@ import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.notification.InflationException; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGuts; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java index 19d90f083592..76c524be1b8f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java @@ -32,7 +32,6 @@ import android.annotation.MainThread; import android.annotation.Nullable; import android.util.ArrayMap; -import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder; import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener; import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener; import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener; @@ -41,6 +40,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.SectionsProvider; +import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener; import com.android.systemui.statusbar.notification.logging.NotifEvent; import com.android.systemui.statusbar.notification.logging.NotifLog; import com.android.systemui.util.Assert; @@ -57,11 +57,13 @@ import javax.inject.Inject; import javax.inject.Singleton; /** - * The implementation of {@link NotifListBuilder}. + * The second half of {@link NotifPipeline}. Sits downstream of the NotifCollection and transforms + * its "notification set" into the "shade list", the filtered, grouped, and sorted list of + * notifications that are currently present in the notification shade. */ @MainThread @Singleton -public class NotifListBuilderImpl implements NotifListBuilder { +public class ShadeListBuilder { private final SystemClock mSystemClock; private final NotifLog mNotifLog; @@ -90,7 +92,7 @@ public class NotifListBuilderImpl implements NotifListBuilder { private final List<ListEntry> mReadOnlyNotifList = Collections.unmodifiableList(mNotifList); @Inject - public NotifListBuilderImpl(SystemClock systemClock, NotifLog notifLog) { + public ShadeListBuilder(SystemClock systemClock, NotifLog notifLog) { Assert.isMainThread(); mSystemClock = systemClock; mNotifLog = notifLog; @@ -116,32 +118,28 @@ public class NotifListBuilderImpl implements NotifListBuilder { mOnRenderListListener = onRenderListListener; } - @Override - public void addOnBeforeTransformGroupsListener(OnBeforeTransformGroupsListener listener) { + void addOnBeforeTransformGroupsListener(OnBeforeTransformGroupsListener listener) { Assert.isMainThread(); mPipelineState.requireState(STATE_IDLE); mOnBeforeTransformGroupsListeners.add(listener); } - @Override - public void addOnBeforeSortListener(OnBeforeSortListener listener) { + void addOnBeforeSortListener(OnBeforeSortListener listener) { Assert.isMainThread(); mPipelineState.requireState(STATE_IDLE); mOnBeforeSortListeners.add(listener); } - @Override - public void addOnBeforeRenderListListener(OnBeforeRenderListListener listener) { + void addOnBeforeRenderListListener(OnBeforeRenderListListener listener) { Assert.isMainThread(); mPipelineState.requireState(STATE_IDLE); mOnBeforeRenderListListeners.add(listener); } - @Override - public void addPreGroupFilter(NotifFilter filter) { + void addPreGroupFilter(NotifFilter filter) { Assert.isMainThread(); mPipelineState.requireState(STATE_IDLE); @@ -149,8 +147,7 @@ public class NotifListBuilderImpl implements NotifListBuilder { filter.setInvalidationListener(this::onPreGroupFilterInvalidated); } - @Override - public void addPreRenderFilter(NotifFilter filter) { + void addPreRenderFilter(NotifFilter filter) { Assert.isMainThread(); mPipelineState.requireState(STATE_IDLE); @@ -158,8 +155,7 @@ public class NotifListBuilderImpl implements NotifListBuilder { filter.setInvalidationListener(this::onPreRenderFilterInvalidated); } - @Override - public void addPromoter(NotifPromoter promoter) { + void addPromoter(NotifPromoter promoter) { Assert.isMainThread(); mPipelineState.requireState(STATE_IDLE); @@ -167,8 +163,7 @@ public class NotifListBuilderImpl implements NotifListBuilder { promoter.setInvalidationListener(this::onPromoterInvalidated); } - @Override - public void setSectionsProvider(SectionsProvider provider) { + void setSectionsProvider(SectionsProvider provider) { Assert.isMainThread(); mPipelineState.requireState(STATE_IDLE); @@ -176,8 +171,7 @@ public class NotifListBuilderImpl implements NotifListBuilder { provider.setInvalidationListener(this::onSectionsProviderInvalidated); } - @Override - public void setComparators(List<NotifComparator> comparators) { + void setComparators(List<NotifComparator> comparators) { Assert.isMainThread(); mPipelineState.requireState(STATE_IDLE); @@ -188,8 +182,7 @@ public class NotifListBuilderImpl implements NotifListBuilder { } } - @Override - public List<ListEntry> getActiveNotifs() { + List<ListEntry> getShadeList() { Assert.isMainThread(); return mReadOnlyNotifList; } @@ -275,7 +268,7 @@ public class NotifListBuilderImpl implements NotifListBuilder { } /** - * The core algorithm of the pipeline. See the top comment in {@link NotifListBuilder} for + * The core algorithm of the pipeline. See the top comment in {@link NotifPipeline} for * details on our contracts with other code. * * Once the build starts we are very careful to protect against reentrant code. Anything that diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CoalescedEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/CoalescedEvent.kt index b6218b4a9c47..143de8a27816 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CoalescedEvent.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/CoalescedEvent.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification.collection.notifcollection +package com.android.systemui.statusbar.notification.collection.coalescer import android.service.notification.NotificationListenerService.Ranking import android.service.notification.StatusBarNotification diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/EventBatch.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java index ac51178e26d7..2c6a165cc550 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/EventBatch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification.collection.notifcollection; +package com.android.systemui.statusbar.notification.collection.coalescer; import java.util.ArrayList; import java.util.List; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java index c3e3c5373b7b..8076616de05e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification.collection.notifcollection; +package com.android.systemui.statusbar.notification.collection.coalescer; import static com.android.systemui.statusbar.notification.logging.NotifEvent.COALESCED_EVENT; import static com.android.systemui.statusbar.notification.logging.NotifEvent.EARLY_BATCH_EMIT; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java index 898918eb076d..c1a11b2f64c8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java @@ -16,27 +16,16 @@ package com.android.systemui.statusbar.notification.collection.coordinator; -import com.android.systemui.statusbar.notification.collection.NotifCollection; -import com.android.systemui.statusbar.notification.collection.NotifCollectionListener; -import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender; -import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline; -import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable; /** - * Interface for registering callbacks to the {@link NewNotifPipeline}. - * - * This includes registering: - * {@link Pluggable}s to the {@link NotifListBuilder} - * {@link NotifCollectionListener}s and {@link NotifLifetimeExtender}s to {@link NotifCollection} + * Interface for registering callbacks to the {@link NotifPipeline}. */ public interface Coordinator { - /** * Called after the NewNotifPipeline is initialized. - * Coordinators should register their {@link Pluggable}s to the notifListBuilder - * and their {@link NotifCollectionListener}s and {@link NotifLifetimeExtender}s - * to the notifCollection in this method. + * Coordinators should register their listeners and {@link Pluggable}s to the pipeline. */ - void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder); + void attach(NotifPipeline pipeline); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java index 5e7dd98fa9da..625d1b9686e9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java @@ -23,9 +23,8 @@ import android.content.pm.PackageManager; import android.os.RemoteException; import android.service.notification.StatusBarNotification; -import com.android.systemui.statusbar.notification.collection.NotifCollection; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -52,10 +51,10 @@ public class DeviceProvisionedCoordinator implements Coordinator { } @Override - public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) { + public void attach(NotifPipeline pipeline) { mDeviceProvisionedController.addCallback(mDeviceProvisionedListener); - notifListBuilder.addPreGroupFilter(mNotifFilter); + pipeline.addPreGroupFilter(mNotifFilter); } private final NotifFilter mNotifFilter = new NotifFilter(TAG) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java index 62342b13f9cf..da119c1502c6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java @@ -25,12 +25,11 @@ import android.util.ArraySet; import com.android.systemui.ForegroundServiceController; import com.android.systemui.appops.AppOpsController; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.statusbar.notification.collection.NotifCollection; -import com.android.systemui.statusbar.notification.collection.NotifCollectionListener; -import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; import java.util.HashMap; import java.util.Map; @@ -57,7 +56,7 @@ public class ForegroundCoordinator implements Coordinator { private final AppOpsController mAppOpsController; private final Handler mMainHandler; - private NotifCollection mNotifCollection; + private NotifPipeline mNotifPipeline; @Inject public ForegroundCoordinator( @@ -70,20 +69,20 @@ public class ForegroundCoordinator implements Coordinator { } @Override - public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) { - mNotifCollection = notifCollection; + public void attach(NotifPipeline pipeline) { + mNotifPipeline = pipeline; // extend the lifetime of foreground notification services to show for at least 5 seconds - mNotifCollection.addNotificationLifetimeExtender(mForegroundLifetimeExtender); + mNotifPipeline.addNotificationLifetimeExtender(mForegroundLifetimeExtender); // listen for new notifications to add appOps - mNotifCollection.addCollectionListener(mNotifCollectionListener); + mNotifPipeline.addCollectionListener(mNotifCollectionListener); // when appOps change, update any relevant notifications to update appOps for mAppOpsController.addCallback(ForegroundServiceController.APP_OPS, this::onAppOpsChanged); // filter out foreground service notifications that aren't necessary anymore - notifListBuilder.addPreGroupFilter(mNotifFilter); + mNotifPipeline.addPreGroupFilter(mNotifFilter); } /** @@ -230,7 +229,7 @@ public class ForegroundCoordinator implements Coordinator { } private NotificationEntry findNotificationEntryWithKey(String key) { - for (NotificationEntry entry : mNotifCollection.getNotifs()) { + for (NotificationEntry entry : mNotifPipeline.getActiveNotifs()) { if (entry.getKey().equals(key)) { return entry; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java index db107f531e9e..a26ee5450d60 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java @@ -39,9 +39,8 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.ListEntry; -import com.android.systemui.statusbar.notification.collection.NotifCollection; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -86,9 +85,9 @@ public class KeyguardCoordinator implements Coordinator { } @Override - public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) { + public void attach(NotifPipeline pipeline) { setupInvalidateNotifListCallbacks(); - notifListBuilder.addPreRenderFilter(mNotifFilter); + pipeline.addPreRenderFilter(mNotifFilter); } private final NotifFilter mNotifFilter = new NotifFilter(TAG) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java index 2436bb9f82f0..562a618126de 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java @@ -18,11 +18,10 @@ package com.android.systemui.statusbar.notification.collection.coordinator; import com.android.systemui.Dumpable; import com.android.systemui.statusbar.FeatureFlags; -import com.android.systemui.statusbar.notification.collection.NotifCollection; -import com.android.systemui.statusbar.notification.collection.NotifCollectionListener; -import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender; -import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -33,8 +32,8 @@ import javax.inject.Inject; import javax.inject.Singleton; /** - * Handles the attachment of the {@link NotifListBuilder} and {@link NotifCollection} to the - * {@link Coordinator}s, so that the Coordinators can register their respective callbacks. + * Handles the attachment of {@link Coordinator}s to the {@link NotifPipeline} so that the + * Coordinators can register their respective callbacks. */ @Singleton public class NotifCoordinators implements Dumpable { @@ -63,14 +62,12 @@ public class NotifCoordinators implements Dumpable { } /** - * Sends the initialized notifListBuilder and notifCollection to each - * coordinator to indicate the notifListBuilder is ready to accept {@link Pluggable}s - * and the notifCollection is ready to accept {@link NotifCollectionListener}s and - * {@link NotifLifetimeExtender}s. + * Sends the pipeline to each coordinator when the pipeline is ready to accept + * {@link Pluggable}s, {@link NotifCollectionListener}s and {@link NotifLifetimeExtender}s. */ - public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) { + public void attach(NotifPipeline pipeline) { for (Coordinator c : mCoordinators) { - c.attach(notifCollection, notifListBuilder); + c.attach(pipeline); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java index a14f0e1cf631..20c9cbc8790d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java @@ -16,13 +16,12 @@ package com.android.systemui.statusbar.notification.collection.coordinator; -import com.android.systemui.statusbar.notification.collection.NotifCollection; -import com.android.systemui.statusbar.notification.collection.NotifCollectionListener; -import com.android.systemui.statusbar.notification.collection.NotifInflater; import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder; +import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.logging.NotifEvent; import com.android.systemui.statusbar.notification.logging.NotifLog; @@ -55,10 +54,10 @@ public class PreparationCoordinator implements Coordinator { } @Override - public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) { - notifCollection.addCollectionListener(mNotifCollectionListener); - notifListBuilder.addPreRenderFilter(mNotifInflationErrorFilter); - notifListBuilder.addPreRenderFilter(mNotifInflatingFilter); + public void attach(NotifPipeline pipeline) { + pipeline.addCollectionListener(mNotifCollectionListener); + pipeline.addPreRenderFilter(mNotifInflationErrorFilter); + pipeline.addPreRenderFilter(mNotifInflatingFilter); } private final NotifCollectionListener mNotifCollectionListener = new NotifCollectionListener() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java index 0751aa814215..7e9e76096873 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java @@ -17,9 +17,8 @@ package com.android.systemui.statusbar.notification.collection.coordinator; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.notification.collection.NotifCollection; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; import javax.inject.Inject; @@ -43,10 +42,10 @@ public class RankingCoordinator implements Coordinator { } @Override - public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) { + public void attach(NotifPipeline pipeline) { mStatusBarStateController.addCallback(mStatusBarStateCallback); - notifListBuilder.addPreGroupFilter(mNotifFilter); + pipeline.addPreGroupFilter(mNotifFilter); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.java index fc04827a9d6a..ea0ece444a67 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.java @@ -14,7 +14,8 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification.collection; +package com.android.systemui.statusbar.notification.collection.inflation; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.coordinator.PreparationCoordinator; /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java index 7504e863ca73..3f500644b184 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,13 +14,14 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification.collection; +package com.android.systemui.statusbar.notification.collection.inflation; import android.annotation.Nullable; import com.android.systemui.statusbar.NotificationUiAdjustment; import com.android.systemui.statusbar.notification.InflationException; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; /** * Used by the {@link NotificationEntryManager}. When notifications are added or updated, the binder diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java index 80b5b8af28ac..1ab20a95ca6c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification.collection; +package com.android.systemui.statusbar.notification.collection.inflation; import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT; @@ -39,6 +39,7 @@ import com.android.systemui.statusbar.NotificationUiAdjustment; import com.android.systemui.statusbar.notification.InflationException; import com.android.systemui.statusbar.notification.NotificationClicker; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/FakePipelineConsumer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/FakePipelineConsumer.java index 986ee17cc906..15f312dbdc00 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/FakePipelineConsumer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/FakePipelineConsumer.java @@ -19,8 +19,8 @@ package com.android.systemui.statusbar.notification.collection.init; import com.android.systemui.Dumpable; import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.ListEntry; -import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.ShadeListBuilder; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -36,7 +36,7 @@ public class FakePipelineConsumer implements Dumpable { private List<ListEntry> mEntries = Collections.emptyList(); /** Attach the consumer to the pipeline. */ - public void attach(NotifListBuilderImpl listBuilder) { + public void attach(ShadeListBuilder listBuilder) { listBuilder.setOnRenderListListener(this::onBuildComplete); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java index 8d3d0ff43deb..959b00211c63 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java @@ -24,10 +24,11 @@ import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl; -import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl; -import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; +import com.android.systemui.statusbar.notification.collection.ShadeListBuilder; +import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer; import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators; -import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -39,10 +40,11 @@ import javax.inject.Singleton; * Initialization code for the new notification pipeline. */ @Singleton -public class NewNotifPipeline implements Dumpable { +public class NotifPipelineInitializer implements Dumpable { + private final NotifPipeline mPipelineWrapper; private final GroupCoalescer mGroupCoalescer; private final NotifCollection mNotifCollection; - private final NotifListBuilderImpl mNotifPipeline; + private final ShadeListBuilder mListBuilder; private final NotifCoordinators mNotifPluggableCoordinators; private final NotifInflaterImpl mNotifInflater; private final DumpController mDumpController; @@ -51,17 +53,19 @@ public class NewNotifPipeline implements Dumpable { private final FakePipelineConsumer mFakePipelineConsumer = new FakePipelineConsumer(); @Inject - public NewNotifPipeline( + public NotifPipelineInitializer( + NotifPipeline pipelineWrapper, GroupCoalescer groupCoalescer, NotifCollection notifCollection, - NotifListBuilderImpl notifPipeline, + ShadeListBuilder listBuilder, NotifCoordinators notifCoordinators, NotifInflaterImpl notifInflater, DumpController dumpController, FeatureFlags featureFlags) { + mPipelineWrapper = pipelineWrapper; mGroupCoalescer = groupCoalescer; mNotifCollection = notifCollection; - mNotifPipeline = notifPipeline; + mListBuilder = listBuilder; mNotifPluggableCoordinators = notifCoordinators; mDumpController = dumpController; mNotifInflater = notifInflater; @@ -81,11 +85,11 @@ public class NewNotifPipeline implements Dumpable { } // Wire up coordinators - mFakePipelineConsumer.attach(mNotifPipeline); - mNotifPluggableCoordinators.attach(mNotifCollection, mNotifPipeline); + mNotifPluggableCoordinators.attach(mPipelineWrapper); // Wire up pipeline - mNotifPipeline.attach(mNotifCollection); + mFakePipelineConsumer.attach(mListBuilder); + mListBuilder.attach(mNotifCollection); mNotifCollection.attach(mGroupCoalescer); mGroupCoalescer.attach(notificationService); @@ -99,5 +103,5 @@ public class NewNotifPipeline implements Dumpable { mGroupCoalescer.dump(fd, pw, args); } - private static final String TAG = "NewNotifPipeline"; + private static final String TAG = "NotifPipeline"; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifListBuilder.java deleted file mode 100644 index 758092417ae0..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifListBuilder.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.notification.collection.listbuilder; - -import com.android.systemui.statusbar.notification.collection.ListEntry; -import com.android.systemui.statusbar.notification.collection.NotifCollection; -import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator; -import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; -import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; -import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.SectionsProvider; - -import java.util.List; - -/** - * The system that constructs the current "notification list", the list of notifications that are - * currently being displayed to the user. - * - * The pipeline proceeds through a series of stages in order to produce the final list (see below). - * Each stage exposes hooks and listeners for other code to participate. - * - * This list differs from the canonical one we receive from system server in a few ways: - * - Filtered: Some notifications are filtered out. For example, we filter out notifications whose - * views haven't been inflated yet. We also filter out some notifications if we're on the lock - * screen. To participate, see {@link #addFilter(NotifFilter)}. - * - Grouped: Notifications that are part of the same group are clustered together into a single - * GroupEntry. These groups are then transformed in order to remove children or completely split - * them apart. To participate, see {@link #addPromoter(NotifPromoter)}. - * - Sorted: All top-level notifications are sorted. To participate, see - * {@link #setSectionsProvider(SectionsProvider)} and {@link #setComparators(List)} - * - * The exact order of all hooks is as follows: - * 0. Collection listeners are fired (see {@link NotifCollection}). - * 1. NotifFilters are called on each notification currently in NotifCollection. - * 2. Initial grouping is performed (NotificationEntries will have their parents set - * appropriately). - * 3. OnBeforeTransformGroupListeners are fired - * 4. NotifPromoters are called on each notification with a parent - * 5. OnBeforeSortListeners are fired - * 6. SectionsProvider is called on each top-level entry in the list - * 7. The top-level entries are sorted using the provided NotifComparators (plus some additional - * built-in logic). - * 8. OnBeforeRenderListListeners are fired - * 9. The list is handed off to the view layer to be rendered. - */ -public interface NotifListBuilder { - - /** - * Registers a filter with the pipeline before grouping, promoting and sorting occurs. Filters - * are called on each notification in the order that they were registered. If any filter - * returns true, the notification is removed from the pipeline (and no other filters are - * called on that notif). - */ - void addPreGroupFilter(NotifFilter filter); - - /** - * Registers a promoter with the pipeline. Promoters are able to promote child notifications to - * top-level, i.e. move a notification that would be a child of a group and make it appear - * ungrouped. Promoters are called on each child notification in the order that they are - * registered. If any promoter returns true, the notification is removed from the group (and no - * other promoters are called on it). - */ - void addPromoter(NotifPromoter promoter); - - /** - * Assigns sections to each top-level entry, where a section is simply an integer. Sections are - * the primary metric by which top-level entries are sorted; NotifComparators are only consulted - * when two entries are in the same section. The pipeline doesn't assign any particular meaning - * to section IDs -- from it's perspective they're just numbers and it sorts them by a simple - * numerical comparison. - */ - void setSectionsProvider(SectionsProvider provider); - - /** - * Comparators that are used to sort top-level entries that share the same section. The - * comparators are executed in order until one of them returns a non-zero result. If all return - * zero, the pipeline falls back to sorting by rank (and, failing that, Notification.when). - */ - void setComparators(List<NotifComparator> comparators); - - /** - * Registers a filter with the pipeline to filter right before rendering the list (after - * pre-group filtering, grouping, promoting and sorting occurs). Filters are - * called on each notification in the order that they were registered. If any filter returns - * true, the notification is removed from the pipeline (and no other filters are called on that - * notif). - */ - void addPreRenderFilter(NotifFilter filter); - - /** - * Called after notifications have been filtered and after the initial grouping has been - * performed but before NotifPromoters have had a chance to promote children out of groups. - */ - void addOnBeforeTransformGroupsListener(OnBeforeTransformGroupsListener listener); - - /** - * Called after notifs have been filtered and groups have been determined but before sections - * have been determined or the notifs have been sorted. - */ - void addOnBeforeSortListener(OnBeforeSortListener listener); - - /** - * Called at the end of the pipeline after the notif list has been finalized but before it has - * been handed off to the view layer. - */ - void addOnBeforeRenderListListener(OnBeforeRenderListListener listener); - - /** - * Returns a read-only view in to the current notification list. If this method is called - * during pipeline execution it will return the current state of the list, which will likely - * be only partially-generated. - */ - List<ListEntry> getActiveNotifs(); -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeRenderListListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeRenderListListener.java index f6ca12d83fdd..44a27a4b546a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeRenderListListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeRenderListListener.java @@ -17,10 +17,11 @@ package com.android.systemui.statusbar.notification.collection.listbuilder; import com.android.systemui.statusbar.notification.collection.ListEntry; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import java.util.List; -/** See {@link NotifListBuilder#addOnBeforeRenderListListener(OnBeforeRenderListListener)} */ +/** See {@link NotifPipeline#addOnBeforeRenderListListener(OnBeforeRenderListListener)} */ public interface OnBeforeRenderListListener { /** * Called at the end of the pipeline after the notif list has been finalized but before it has diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeSortListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeSortListener.java index 7be7ac03e1f1..56cfe5cb3716 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeSortListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeSortListener.java @@ -17,10 +17,11 @@ package com.android.systemui.statusbar.notification.collection.listbuilder; import com.android.systemui.statusbar.notification.collection.ListEntry; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import java.util.List; -/** See {@link NotifListBuilder#addOnBeforeSortListener(OnBeforeSortListener)} */ +/** See {@link NotifPipeline#addOnBeforeSortListener(OnBeforeSortListener)} */ public interface OnBeforeSortListener { /** * Called after the notif list has been filtered and grouped but before sections have been diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeTransformGroupsListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeTransformGroupsListener.java index d7a081510655..0dc4df0da066 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeTransformGroupsListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeTransformGroupsListener.java @@ -17,13 +17,14 @@ package com.android.systemui.statusbar.notification.collection.listbuilder; import com.android.systemui.statusbar.notification.collection.ListEntry; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; import java.util.List; /** * See - * {@link NotifListBuilder#addOnBeforeTransformGroupsListener(OnBeforeTransformGroupsListener)} + * {@link NotifPipeline#addOnBeforeTransformGroupsListener(OnBeforeTransformGroupsListener)} */ public interface OnBeforeTransformGroupsListener { /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java index 084d03810ad9..1897ba2319ac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java @@ -18,13 +18,13 @@ package com.android.systemui.statusbar.notification.collection.listbuilder; import android.annotation.IntDef; -import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl; +import com.android.systemui.statusbar.notification.collection.ShadeListBuilder; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * Used by {@link NotifListBuilderImpl} to track its internal state machine. + * Used by {@link ShadeListBuilder} to track its internal state machine. */ public class PipelineState { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifComparator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifComparator.java index a191c830537d..0d150edee128 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifComparator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifComparator.java @@ -17,13 +17,13 @@ package com.android.systemui.statusbar.notification.collection.listbuilder.pluggable; import com.android.systemui.statusbar.notification.collection.ListEntry; -import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import java.util.Comparator; import java.util.List; /** - * Pluggable for participating in notif sorting. See {@link NotifListBuilder#setComparators(List)}. + * Pluggable for participating in notif sorting. See {@link NotifPipeline#setComparators(List)}. */ public abstract class NotifComparator extends Pluggable<NotifComparator> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java index e6189edc2f3b..8f575cdd8918 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java @@ -16,12 +16,12 @@ package com.android.systemui.statusbar.notification.collection.listbuilder.pluggable; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder; /** * Pluggable for participating in notif filtering. - * See {@link NotifListBuilder#addPreGroupFilter} and {@link NotifListBuilder#addPreRenderFilter}. + * See {@link NotifPipeline#addPreGroupFilter} and {@link NotifPipeline#addPreRenderFilter}. */ public abstract class NotifFilter extends Pluggable<NotifFilter> { protected NotifFilter(String name) { @@ -35,9 +35,9 @@ public abstract class NotifFilter extends Pluggable<NotifFilter> { * however. If another filter returns true before yours, we'll skip straight to the next notif. * * @param entry The entry in question. - * If this filter is registered via {@link NotifListBuilder#addPreGroupFilter}, + * If this filter is registered via {@link NotifPipeline#addPreGroupFilter}, * this entry will not have any grouping nor sorting information. - * If this filter is registered via {@link NotifListBuilder#addPreRenderFilter}, + * If this filter is registered via {@link NotifPipeline#addPreRenderFilter}, * this entry will have grouping and sorting information. * @param now A timestamp in SystemClock.uptimeMillis that represents "now" for the purposes of * pipeline execution. This value will be the same for all pluggable calls made diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifPromoter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifPromoter.java index 84e16f432740..5fce4462aede 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifPromoter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifPromoter.java @@ -16,13 +16,13 @@ package com.android.systemui.statusbar.notification.collection.listbuilder.pluggable; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder; /** * Pluggable for participating in notif promotion. Notif promoters can upgrade notifications * from being children of a group to top-level notifications. See - * {@link NotifListBuilder#addPromoter(NotifPromoter)}. + * {@link NotifPipeline#addPromoter}. */ public abstract class NotifPromoter extends Pluggable<NotifPromoter> { protected NotifPromoter(String name) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java index f9ce197c6547..4270408d0c66 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java @@ -18,10 +18,10 @@ package com.android.systemui.statusbar.notification.collection.listbuilder.plugg import android.annotation.Nullable; -import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; /** - * Generic superclass for chunks of code that can plug into the {@link NotifListBuilder}. + * Generic superclass for chunks of code that can plug into the {@link NotifPipeline}. * * A pluggable is fundamentally three things: * 1. A name (for debugging purposes) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/CollectionReadyForBuildListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CollectionReadyForBuildListener.java index 87aaea007e65..4023474bf6a7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/CollectionReadyForBuildListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CollectionReadyForBuildListener.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,9 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification.collection; +package com.android.systemui.statusbar.notification.collection.notifcollection; + +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import java.util.Collection; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/DismissedByUserStats.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/DismissedByUserStats.java index ecce6ea1b211..b2686864cc43 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/DismissedByUserStats.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/DismissedByUserStats.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification.collection; +package com.android.systemui.statusbar.notification.collection.notifcollection; import android.service.notification.NotificationStats.DismissalSentiment; import android.service.notification.NotificationStats.DismissalSurface; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollectionListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java index 032620e14336..9cbc7d7efa66 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollectionListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,9 +14,11 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification.collection; +package com.android.systemui.statusbar.notification.collection.notifcollection; +import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; /** * Listener interface for {@link NotifCollection}. @@ -36,7 +38,9 @@ public interface NotifCollectionListener { } /** - * Called immediately after a notification has been removed from the collection. + * Called whenever a notification is retracted by system server. This method is not called + * immediately after a user dismisses a notification: we wait until we receive confirmation from + * system server before considering the notification removed. */ default void onEntryRemoved( NotificationEntry entry, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java index 2c7b13866c10..05f5ea85bd4d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifLifetimeExtender.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,9 +14,11 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification.collection; +package com.android.systemui.statusbar.notification.collection.notifcollection; +import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; /** * A way for other code to temporarily extend the lifetime of a notification after it has been diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java index c6c36ee17873..02acc8149cc4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java @@ -22,8 +22,8 @@ import android.service.notification.StatusBarNotification; import com.android.systemui.log.RichEvent; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder; -import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer; +import com.android.systemui.statusbar.notification.collection.ShadeListBuilder; +import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -67,7 +67,7 @@ public class NotifEvent extends RichEvent { } /** - * @return if this event occurred in {@link NotifListBuilder} + * @return if this event occurred in {@link ShadeListBuilder} */ static boolean isListBuilderEvent(@EventType int type) { return isBetweenInclusive(type, 0, TOTAL_LIST_BUILDER_EVENT_TYPES); @@ -161,7 +161,7 @@ public class NotifEvent extends RichEvent { private static final int TOTAL_EVENT_LABELS = EVENT_LABELS.length; /** - * Events related to {@link NotifListBuilder} + * Events related to {@link ShadeListBuilder} */ public static final int WARN = 0; public static final int ON_BUILD_LIST = 1; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt index 78eaf3ee10a4..452d1eb95aab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt @@ -17,7 +17,9 @@ package com.android.systemui.statusbar.notification.people import android.app.Notification +import android.content.Context import android.service.notification.StatusBarNotification +import android.util.FeatureFlagUtils import javax.inject.Inject import javax.inject.Singleton @@ -27,10 +29,16 @@ interface PeopleNotificationIdentifier { @Singleton class PeopleNotificationIdentifierImpl @Inject constructor( - private val personExtractor: NotificationPersonExtractor + private val personExtractor: NotificationPersonExtractor, + private val context: Context ) : PeopleNotificationIdentifier { override fun isPeopleNotification(sbn: StatusBarNotification) = - sbn.notification.notificationStyle == Notification.MessagingStyle::class.java || + (sbn.notification.notificationStyle == Notification.MessagingStyle::class.java && + (sbn.notification.shortcutId != null || + FeatureFlagUtils.isEnabled( + context, + FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ + ))) || personExtractor.isPersonNotification(sbn) }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 189d3b6f530b..ba70cf4a39f4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -199,8 +199,8 @@ import com.android.systemui.statusbar.notification.NotificationListController; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl; -import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; +import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; @@ -364,7 +364,7 @@ public class StatusBar extends SystemUI implements DemoMode, private final HeadsUpManagerPhone mHeadsUpManager; private final DynamicPrivacyController mDynamicPrivacyController; private final BypassHeadsUpNotifier mBypassHeadsUpNotifier; - private final Lazy<NewNotifPipeline> mNewNotifPipeline; + private final Lazy<NotifPipelineInitializer> mNewNotifPipeline; private final FalsingManager mFalsingManager; private final BroadcastDispatcher mBroadcastDispatcher; private final ConfigurationController mConfigurationController; @@ -625,7 +625,7 @@ public class StatusBar extends SystemUI implements DemoMode, HeadsUpManagerPhone headsUpManagerPhone, DynamicPrivacyController dynamicPrivacyController, BypassHeadsUpNotifier bypassHeadsUpNotifier, - Lazy<NewNotifPipeline> newNotifPipeline, + Lazy<NotifPipelineInitializer> newNotifPipeline, FalsingManager falsingManager, BroadcastDispatcher broadcastDispatcher, RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java index be7f0a0c36f2..b4d5dadda5b8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java @@ -65,8 +65,8 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl; -import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; +import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; @@ -117,7 +117,7 @@ public class StatusBarModule { HeadsUpManagerPhone headsUpManagerPhone, DynamicPrivacyController dynamicPrivacyController, BypassHeadsUpNotifier bypassHeadsUpNotifier, - Lazy<NewNotifPipeline> newNotifPipeline, + Lazy<NotifPipelineInitializer> newNotifPipeline, FalsingManager falsingManager, BroadcastDispatcher broadcastDispatcher, RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index 12a65169e1df..720f22964915 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -66,7 +66,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java index 9c9a627fa6e0..8d11b54dacb2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java @@ -48,7 +48,7 @@ import com.android.internal.messages.nano.SystemMessageProto; import com.android.systemui.appops.AppOpsController; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.collection.NotifCollection; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; @@ -71,7 +71,7 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { @Mock private NotificationEntryManager mEntryManager; @Mock private AppOpsController mAppOpsController; @Mock private Handler mMainHandler; - @Mock private NotifCollection mNotifCollection; + @Mock private NotifPipeline mNotifPipeline; @Before public void setUp() throws Exception { @@ -81,7 +81,7 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); mFsc = new ForegroundServiceController(mEntryManager, mAppOpsController, mMainHandler); mListener = new ForegroundServiceNotificationListener( - mContext, mFsc, mEntryManager, mNotifCollection); + mContext, mFsc, mEntryManager, mNotifPipeline); ArgumentCaptor<NotificationEntryListener> entryListenerCaptor = ArgumentCaptor.forClass(NotificationEntryListener.class); verify(mEntryManager).addNotificationEntryListener( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index 1e0179dc92f1..cc5514f1ff68 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -78,7 +78,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager.Keyg import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; -import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import com.android.systemui.statusbar.notification.logging.NotifLog; import com.android.systemui.statusbar.notification.logging.NotificationLogger; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt index bf84f2bc599c..29ce92074027 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt @@ -21,7 +21,7 @@ import com.android.systemui.statusbar.NotificationPresenter import com.android.systemui.statusbar.NotificationRemoteInputManager import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.NotificationRankingManager -import com.android.systemui.statusbar.notification.collection.NotificationRowBinder +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder import com.android.systemui.statusbar.notification.logging.NotifLog import com.android.systemui.statusbar.notification.stack.NotificationListContainer import com.android.systemui.statusbar.phone.HeadsUpManagerPhone diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java index 28feacac8c44..09cc5ba204f8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java @@ -52,9 +52,13 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent; import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason; -import com.android.systemui.statusbar.notification.collection.notifcollection.CoalescedEvent; -import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer; -import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer.BatchableNotificationHandler; +import com.android.systemui.statusbar.notification.collection.coalescer.CoalescedEvent; +import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer; +import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer.BatchableNotificationHandler; +import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener; +import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; import com.android.systemui.util.Assert; import org.junit.Before; @@ -377,7 +381,7 @@ public class NotifCollectionTest extends SysuiTestCase { verify(mExtender3).shouldExtendLifetime(entry2, REASON_UNKNOWN); // THEN the entry is not removed - assertTrue(mCollection.getNotifs().contains(entry2)); + assertTrue(mCollection.getActiveNotifs().contains(entry2)); // THEN the entry properly records all extenders that returned true assertEquals(Arrays.asList(mExtender1, mExtender2), entry2.mLifetimeExtenders); @@ -398,7 +402,7 @@ public class NotifCollectionTest extends SysuiTestCase { // GIVEN a notification gets lifetime-extended by one of them mNoMan.retractNotif(notif2.sbn, REASON_APP_CANCEL); - assertTrue(mCollection.getNotifs().contains(entry2)); + assertTrue(mCollection.getActiveNotifs().contains(entry2)); clearInvocations(mExtender1, mExtender2, mExtender3); // WHEN the last active extender expires (but new ones become active) @@ -413,7 +417,7 @@ public class NotifCollectionTest extends SysuiTestCase { verify(mExtender3).shouldExtendLifetime(entry2, REASON_UNKNOWN); // THEN the entry is not removed - assertTrue(mCollection.getNotifs().contains(entry2)); + assertTrue(mCollection.getActiveNotifs().contains(entry2)); // THEN the entry properly records all extenders that returned true assertEquals(Arrays.asList(mExtender1, mExtender3), entry2.mLifetimeExtenders); @@ -435,7 +439,7 @@ public class NotifCollectionTest extends SysuiTestCase { // GIVEN a notification gets lifetime-extended by a couple of them mNoMan.retractNotif(notif2.sbn, REASON_APP_CANCEL); - assertTrue(mCollection.getNotifs().contains(entry2)); + assertTrue(mCollection.getActiveNotifs().contains(entry2)); clearInvocations(mExtender1, mExtender2, mExtender3); // WHEN one (but not all) of the extenders expires @@ -443,7 +447,7 @@ public class NotifCollectionTest extends SysuiTestCase { mExtender2.callback.onEndLifetimeExtension(mExtender2, entry2); // THEN the entry is not removed - assertTrue(mCollection.getNotifs().contains(entry2)); + assertTrue(mCollection.getActiveNotifs().contains(entry2)); // THEN we don't re-query the extenders verify(mExtender1, never()).shouldExtendLifetime(eq(entry2), anyInt()); @@ -470,7 +474,7 @@ public class NotifCollectionTest extends SysuiTestCase { // GIVEN a notification gets lifetime-extended by a couple of them mNoMan.retractNotif(notif2.sbn, REASON_UNKNOWN); - assertTrue(mCollection.getNotifs().contains(entry2)); + assertTrue(mCollection.getActiveNotifs().contains(entry2)); clearInvocations(mExtender1, mExtender2, mExtender3); // WHEN all of the active extenders expire @@ -480,7 +484,7 @@ public class NotifCollectionTest extends SysuiTestCase { mExtender1.callback.onEndLifetimeExtension(mExtender1, entry2); // THEN the entry removed - assertFalse(mCollection.getNotifs().contains(entry2)); + assertFalse(mCollection.getActiveNotifs().contains(entry2)); verify(mCollectionListener).onEntryRemoved(entry2, REASON_UNKNOWN, false); } @@ -500,7 +504,7 @@ public class NotifCollectionTest extends SysuiTestCase { // GIVEN a notification gets lifetime-extended by a couple of them mNoMan.retractNotif(notif2.sbn, REASON_UNKNOWN); - assertTrue(mCollection.getNotifs().contains(entry2)); + assertTrue(mCollection.getActiveNotifs().contains(entry2)); clearInvocations(mExtender1, mExtender2, mExtender3); // WHEN the notification is reposted @@ -511,7 +515,7 @@ public class NotifCollectionTest extends SysuiTestCase { verify(mExtender2).cancelLifetimeExtension(entry2); // THEN the notification is still present - assertTrue(mCollection.getNotifs().contains(entry2)); + assertTrue(mCollection.getActiveNotifs().contains(entry2)); } @Test(expected = IllegalStateException.class) @@ -530,7 +534,7 @@ public class NotifCollectionTest extends SysuiTestCase { // GIVEN a notification gets lifetime-extended by a couple of them mNoMan.retractNotif(notif2.sbn, REASON_UNKNOWN); - assertTrue(mCollection.getNotifs().contains(entry2)); + assertTrue(mCollection.getActiveNotifs().contains(entry2)); clearInvocations(mExtender1, mExtender2, mExtender3); // WHEN a lifetime extender makes a reentrant call during cancelLifetimeExtension() @@ -559,7 +563,7 @@ public class NotifCollectionTest extends SysuiTestCase { // GIVEN a notification gets lifetime-extended by a couple of them mNoMan.retractNotif(notif2.sbn, REASON_UNKNOWN); - assertTrue(mCollection.getNotifs().contains(entry2)); + assertTrue(mCollection.getActiveNotifs().contains(entry2)); clearInvocations(mExtender1, mExtender2, mExtender3); // WHEN the notification is reposted diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java index 3e4068b6367c..be067481b779 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java @@ -38,7 +38,7 @@ import android.util.ArrayMap; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; -import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl.OnRenderListListener; +import com.android.systemui.statusbar.notification.collection.ShadeListBuilder.OnRenderListListener; import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener; import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener; import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener; @@ -46,6 +46,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.SectionsProvider; +import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener; import com.android.systemui.statusbar.notification.logging.NotifLog; import com.android.systemui.util.Assert; import com.android.systemui.util.time.FakeSystemClock; @@ -72,9 +73,9 @@ import java.util.stream.Collectors; @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper -public class NotifListBuilderImplTest extends SysuiTestCase { +public class ShadeListBuilderTest extends SysuiTestCase { - private NotifListBuilderImpl mListBuilder; + private ShadeListBuilder mListBuilder; private FakeSystemClock mSystemClock = new FakeSystemClock(); @Mock private NotifLog mNotifLog; @@ -99,7 +100,7 @@ public class NotifListBuilderImplTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); Assert.sMainLooper = TestableLooper.get(this).getLooper(); - mListBuilder = new NotifListBuilderImpl(mSystemClock, mNotifLog); + mListBuilder = new ShadeListBuilder(mSystemClock, mNotifLog); mListBuilder.setOnRenderListListener(mOnRenderListListener); mListBuilder.attach(mNotifCollection); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java index 7ff32401b4be..5e0baf204ecf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification.collection.notifcollection; +package com.android.systemui.statusbar.notification.collection.coalescer; import static com.android.internal.util.Preconditions.checkNotNull; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java index ea6c70a6e142..701cf95736ea 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java @@ -36,7 +36,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.RankingBuilder; -import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; @@ -65,7 +65,7 @@ public class DeviceProvisionedCoordinatorTest extends SysuiTestCase { @Mock private ActivityManagerInternal mActivityMangerInternal; @Mock private IPackageManager mIPackageManager; @Mock private DeviceProvisionedController mDeviceProvisionedController; - @Mock private NotifListBuilderImpl mNotifListBuilder; + @Mock private NotifPipeline mNotifPipeline; private Notification mNotification; private NotificationEntry mEntry; private DeviceProvisionedCoordinator mDeviceProvisionedCoordinator; @@ -84,8 +84,8 @@ public class DeviceProvisionedCoordinatorTest extends SysuiTestCase { .build(); ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class); - mDeviceProvisionedCoordinator.attach(null, mNotifListBuilder); - verify(mNotifListBuilder, times(1)).addPreGroupFilter(filterCaptor.capture()); + mDeviceProvisionedCoordinator.attach(mNotifPipeline); + verify(mNotifPipeline, times(1)).addPreGroupFilter(filterCaptor.capture()); mDeviceProvisionedFilter = filterCaptor.getValue(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java index 01bca0dc1078..6cc8dd908760 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java @@ -36,12 +36,11 @@ import androidx.test.filters.SmallTest; import com.android.systemui.ForegroundServiceController; import com.android.systemui.SysuiTestCase; import com.android.systemui.appops.AppOpsController; -import com.android.systemui.statusbar.notification.collection.NotifCollection; -import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender; -import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; import org.junit.Before; import org.junit.Test; @@ -59,8 +58,7 @@ public class ForegroundCoordinatorTest extends SysuiTestCase { @Mock private Handler mMainHandler; @Mock private ForegroundServiceController mForegroundServiceController; @Mock private AppOpsController mAppOpsController; - @Mock private NotifListBuilderImpl mNotifListBuilder; - @Mock private NotifCollection mNotifCollection; + @Mock private NotifPipeline mNotifPipeline; private NotificationEntry mEntry; private Notification mNotification; @@ -84,9 +82,9 @@ public class ForegroundCoordinatorTest extends SysuiTestCase { ArgumentCaptor<NotifLifetimeExtender> lifetimeExtenderCaptor = ArgumentCaptor.forClass(NotifLifetimeExtender.class); - mForegroundCoordinator.attach(mNotifCollection, mNotifListBuilder); - verify(mNotifListBuilder, times(1)).addPreGroupFilter(filterCaptor.capture()); - verify(mNotifCollection, times(1)).addNotificationLifetimeExtender( + mForegroundCoordinator.attach(mNotifPipeline); + verify(mNotifPipeline, times(1)).addPreGroupFilter(filterCaptor.capture()); + verify(mNotifPipeline, times(1)).addNotificationLifetimeExtender( lifetimeExtenderCaptor.capture()); mForegroundFilter = filterCaptor.getValue(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java index f921cf969e61..5866d90f62bf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java @@ -41,7 +41,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.notification.collection.GroupEntry; -import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; @@ -68,7 +68,7 @@ public class KeyguardCoordinatorTest extends SysuiTestCase { @Mock private StatusBarStateController mStatusBarStateController; @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock private HighPriorityProvider mHighPriorityProvider; - @Mock private NotifListBuilderImpl mNotifListBuilder; + @Mock private NotifPipeline mNotifPipeline; private NotificationEntry mEntry; private KeyguardCoordinator mKeyguardCoordinator; @@ -87,8 +87,8 @@ public class KeyguardCoordinatorTest extends SysuiTestCase { .build(); ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class); - mKeyguardCoordinator.attach(null, mNotifListBuilder); - verify(mNotifListBuilder, times(1)).addPreRenderFilter(filterCaptor.capture()); + mKeyguardCoordinator.attach(mNotifPipeline); + verify(mNotifPipeline, times(1)).addPreRenderFilter(filterCaptor.capture()); mKeyguardFilter = filterCaptor.getValue(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java index d3b16c319692..e84f9cf352ed 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java @@ -33,7 +33,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.RankingBuilder; -import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; @@ -50,7 +50,7 @@ import org.mockito.MockitoAnnotations; public class RankingCoordinatorTest extends SysuiTestCase { @Mock private StatusBarStateController mStatusBarStateController; - @Mock private NotifListBuilderImpl mNotifListBuilder; + @Mock private NotifPipeline mNotifPipeline; private NotificationEntry mEntry; private RankingCoordinator mRankingCoordinator; private NotifFilter mRankingFilter; @@ -62,8 +62,8 @@ public class RankingCoordinatorTest extends SysuiTestCase { mEntry = new NotificationEntryBuilder().build(); ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class); - mRankingCoordinator.attach(null, mNotifListBuilder); - verify(mNotifListBuilder, times(1)).addPreGroupFilter(filterCaptor.capture()); + mRankingCoordinator.attach(mNotifPipeline); + verify(mNotifPipeline, times(1)).addPreGroupFilter(filterCaptor.capture()); mRankingFilter = filterCaptor.getValue(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 9bd3914da3da..d9939f485ce5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -71,7 +71,7 @@ import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; -import com.android.systemui.statusbar.notification.collection.NotificationRowBinder; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import com.android.systemui.statusbar.notification.logging.NotifLog; import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewAdapter; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java index 5ac7bfbfd296..782e14c83951 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java @@ -54,7 +54,7 @@ import com.android.systemui.statusbar.notification.NotificationInterruptionState import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; -import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 560aadb93a14..fee48522683d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -120,8 +120,8 @@ import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; -import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl; -import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline; +import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; +import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; @@ -214,7 +214,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator; @Mock private KeyguardBypassController mKeyguardBypassController; @Mock private DynamicPrivacyController mDynamicPrivacyController; - @Mock private NewNotifPipeline mNewNotifPipeline; + @Mock private NotifPipelineInitializer mNewNotifPipeline; @Mock private ZenModeController mZenModeController; @Mock private AutoHideController mAutoHideController; @Mock private NotificationViewHierarchyManager mNotificationViewHierarchyManager; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java index 4103d7189266..cd89d3c32697 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java @@ -30,12 +30,12 @@ import android.telephony.CellSignalStrength; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; -import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.settingslib.graph.SignalDrawable; import com.android.settingslib.net.DataUsageController; @@ -418,7 +418,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn); intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn); - intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, mSubId); + SubscriptionManager.putSubscriptionIdExtra(intent, mSubId); return intent; } diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index e1fe3bfda4a8..900c67198677 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -501,13 +501,15 @@ public class TetheringTest { p2pInfo.groupFormed = isGroupFormed; p2pInfo.isGroupOwner = isGroupOwner; - WifiP2pGroup group = new WifiP2pGroup(); - group.setIsGroupOwner(isGroupOwner); - group.setInterface(ifname); + WifiP2pGroup group = mock(WifiP2pGroup.class); + when(group.isGroupOwner()).thenReturn(isGroupOwner); + when(group.getInterface()).thenReturn(ifname); + + final Intent intent = mock(Intent.class); + when(intent.getAction()).thenReturn(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); + when(intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO)).thenReturn(p2pInfo); + when(intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP)).thenReturn(group); - final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); - intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, p2pInfo); - intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, group); mServiceContext.sendBroadcastAsUserMultiplePermissions(intent, UserHandle.ALL, P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST); } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index f34b5e71ad7b..7d354d20cb67 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -162,6 +162,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState /** uid the session is for */ public final int uid; + /** user id the session is for */ + public final int userId; + /** ID of the task associated with this session's activity */ public final int taskId; @@ -613,7 +616,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState int newState, int flags) { if (isInlineSuggestionsEnabled()) { mInlineSuggestionsRequestCallback = new InlineSuggestionsRequestCallbackImpl(); - mInputMethodManagerInternal.onCreateInlineSuggestionsRequest( + mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(userId, mComponentName, mCurrentViewId, mInlineSuggestionsRequestCallback); } @@ -759,6 +762,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mFlags = flags; this.taskId = taskId; this.uid = uid; + this.userId = userId; mStartTime = SystemClock.elapsedRealtime(); mService = service; mLock = lock; diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java index eb6262094849..b06fc52a24c2 100644 --- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java +++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java @@ -21,12 +21,10 @@ import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.BackupManagerService.TAG; import android.app.backup.RestoreSet; -import android.content.Intent; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.os.RemoteException; -import android.os.UserHandle; import android.util.EventLog; import android.util.Pair; import android.util.Slog; @@ -40,7 +38,6 @@ import com.android.server.backup.DataChangedJournal; import com.android.server.backup.TransportManager; import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.fullbackup.PerformAdbBackupTask; -import com.android.server.backup.fullbackup.PerformFullTransportBackupTask; import com.android.server.backup.keyvalue.BackupRequest; import com.android.server.backup.keyvalue.KeyValueBackupTask; import com.android.server.backup.params.AdbBackupParams; @@ -73,10 +70,7 @@ public class BackupHandler extends Handler { public static final int MSG_RESTORE_SESSION_TIMEOUT = 8; public static final int MSG_FULL_CONFIRMATION_TIMEOUT = 9; public static final int MSG_RUN_ADB_RESTORE = 10; - public static final int MSG_RETRY_INIT = 11; public static final int MSG_RETRY_CLEAR = 12; - public static final int MSG_WIDGET_BROADCAST = 13; - public static final int MSG_RUN_FULL_TRANSPORT_BACKUP = 14; public static final int MSG_REQUEST_BACKUP = 15; public static final int MSG_SCHEDULE_BACKUP_PACKAGE = 16; public static final int MSG_BACKUP_OPERATION_TIMEOUT = 17; @@ -279,12 +273,6 @@ public class BackupHandler extends Handler { break; } - case MSG_RUN_FULL_TRANSPORT_BACKUP: { - PerformFullTransportBackupTask task = (PerformFullTransportBackupTask) msg.obj; - (new Thread(task, "transport-backup")).start(); - break; - } - case MSG_RUN_RESTORE: { RestoreParams params = (RestoreParams) msg.obj; Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer); @@ -445,12 +433,6 @@ public class BackupHandler extends Handler { break; } - case MSG_WIDGET_BROADCAST: { - final Intent intent = (Intent) msg.obj; - backupManagerService.getContext().sendBroadcastAsUser(intent, UserHandle.SYSTEM); - break; - } - case MSG_REQUEST_BACKUP: { BackupParams params = (BackupParams) msg.obj; if (MORE_DEBUG) { diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index f4962e53662c..5435cbad870f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -5505,7 +5505,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // changes that would conflict throughout the automerger graph. Having this method temporarily // helps with the process of going through with all these dependent changes across the entire // tree. - public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, + /** + * Register a new agent. {@see #registerNetworkAgent} below. + */ + public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkAgentConfig networkAgentConfig) { return registerNetworkAgent(messenger, networkInfo, linkProperties, networkCapabilities, @@ -5526,8 +5529,9 @@ public class ConnectivityService extends IConnectivityManager.Stub * {@link NetworkAgentInfo#getCurrentScore}. * @param networkAgentConfig metadata about the network. This is never updated. * @param providerId the ID of the provider owning this NetworkAgent. + * @return the network created for this agent. */ - public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, + public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) { enforceNetworkFactoryPermission(); @@ -5560,7 +5564,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // If the network disconnects or sends any other event before that, messages are deferred by // NetworkAgent until nai.asyncChannel.connect(), which will be called when finalizing the // registration. - return nai.network.netId; + return nai.network; } private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) { diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java index b26ef92557e1..d1d1cb3566d2 100644 --- a/services/core/java/com/android/server/NetworkScoreService.java +++ b/services/core/java/com/android/server/NetworkScoreService.java @@ -523,7 +523,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub { @Override public void accept(INetworkScoreCache networkScoreCache, Object cookie) { - int filterType = NetworkScoreManager.CACHE_FILTER_NONE; + int filterType = NetworkScoreManager.SCORE_FILTER_NONE; if (cookie instanceof Integer) { filterType = (Integer) cookie; } @@ -547,17 +547,17 @@ public class NetworkScoreService extends INetworkScoreService.Stub { private List<ScoredNetwork> filterScores(List<ScoredNetwork> scoredNetworkList, int filterType) { switch (filterType) { - case NetworkScoreManager.CACHE_FILTER_NONE: + case NetworkScoreManager.SCORE_FILTER_NONE: return scoredNetworkList; - case NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK: + case NetworkScoreManager.SCORE_FILTER_CURRENT_NETWORK: if (mCurrentNetworkFilter == null) { mCurrentNetworkFilter = new CurrentNetworkScoreCacheFilter(new WifiInfoSupplier(mContext)); } return mCurrentNetworkFilter.apply(scoredNetworkList); - case NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS: + case NetworkScoreManager.SCORE_FILTER_SCAN_RESULTS: if (mScanResultsFilter == null) { mScanResultsFilter = new ScanResultsScoreCacheFilter( new ScanResultsSupplier(mContext)); diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java index c27b0da780b7..ed3bab97ca19 100644 --- a/services/core/java/com/android/server/TestNetworkService.java +++ b/services/core/java/com/android/server/TestNetworkService.java @@ -218,7 +218,7 @@ class TestNetworkService extends ITestNetworkManager.Stub { // Has to be in TestNetworkAgent to ensure all teardown codepaths properly clean up // resources, even for binder death or unwanted calls. synchronized (mTestNetworkTracker) { - mTestNetworkTracker.remove(netId); + mTestNetworkTracker.remove(network.netId); } } } @@ -337,7 +337,7 @@ class TestNetworkService extends ITestNetworkManager.Stub { callingUid, binder); - mTestNetworkTracker.put(agent.netId, agent); + mTestNetworkTracker.put(agent.network.netId, agent); } } catch (SocketException e) { throw new UncheckedIOException(e); diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index a372fca07728..debc2a116934 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -2129,16 +2129,6 @@ public class AccountManagerService } @Override - public void removeAccount(IAccountManagerResponse response, Account account, - boolean expectActivityLaunch) { - removeAccountAsUser( - response, - account, - expectActivityLaunch, - UserHandle.getCallingUserId()); - } - - @Override public void removeAccountAsUser(IAccountManagerResponse response, Account account, boolean expectActivityLaunch, int userId) { final int callingUid = Binder.getCallingUid(); @@ -4454,12 +4444,6 @@ public class AccountManagerService @Override @NonNull - public Account[] getAccounts(String type, String opPackageName) { - return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName); - } - - @Override - @NonNull public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) { int callingUid = Binder.getCallingUid(); if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index c21adb08270e..8f6d981064de 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -16408,6 +16408,22 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + public boolean updateMccMncConfiguration(String mcc, String mnc) { + int mccInt, mncInt; + try { + mccInt = Integer.parseInt(mcc); + mncInt = Integer.parseInt(mnc); + } catch (NumberFormatException | StringIndexOutOfBoundsException ex) { + Slog.e(TAG, "Error parsing mcc: " + mcc + " mnc: " + mnc + ". ex=" + ex); + return false; + } + Configuration config = new Configuration(); + config.mcc = mccInt; + config.mnc = mncInt == 0 ? Configuration.MNC_ZERO : mncInt; + return mActivityTaskManager.updateConfiguration(config); + } + + @Override public int getLaunchedFromUid(IBinder activityToken) { return mActivityTaskManager.getLaunchedFromUid(activityToken); } diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java index f15d999e1006..8d261762a19b 100644 --- a/services/core/java/com/android/server/compat/CompatConfig.java +++ b/services/core/java/com/android/server/compat/CompatConfig.java @@ -367,6 +367,8 @@ final class CompatConfig { CompatConfig config = new CompatConfig(androidBuildClassifier, context); config.initConfigFromLib(Environment.buildPath( Environment.getRootDirectory(), "etc", "compatconfig")); + config.initConfigFromLib(Environment.buildPath( + Environment.getRootDirectory(), "system_ext", "etc", "compatconfig")); return config; } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 476f3f823def..1d2a9059c453 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -848,7 +848,7 @@ public class Vpn { } public int getNetId() { - return mNetworkAgent != null ? mNetworkAgent.netId : NETID_UNSET; + return mNetworkAgent != null ? mNetworkAgent.network.netId : NETID_UNSET; } private LinkProperties makeLinkProperties() { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java index 2c3c70fc3da2..9c421524d723 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java @@ -68,8 +68,9 @@ public abstract class InputMethodManagerInternal { * @param autofillId {@link AutofillId} of currently focused field. * @param cb {@link IInlineSuggestionsRequestCallback} used to pass back the request object. */ - public abstract void onCreateInlineSuggestionsRequest(ComponentName componentName, - AutofillId autofillId, IInlineSuggestionsRequestCallback cb); + public abstract void onCreateInlineSuggestionsRequest(@UserIdInt int userId, + ComponentName componentName, AutofillId autofillId, + IInlineSuggestionsRequestCallback cb); /** * Force switch to the enabled input method by {@code imeId} for current user. If the input @@ -107,8 +108,9 @@ public abstract class InputMethodManagerInternal { } @Override - public void onCreateInlineSuggestionsRequest(ComponentName componentName, - AutofillId autofillId, IInlineSuggestionsRequestCallback cb) { + public void onCreateInlineSuggestionsRequest(int userId, + ComponentName componentName, AutofillId autofillId, + IInlineSuggestionsRequestCallback cb) { } @Override diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index d4b13faf3195..0bf65bd6f739 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -111,6 +111,7 @@ import android.view.WindowManager.LayoutParams; import android.view.WindowManager.LayoutParams.SoftInputModeFlags; import android.view.autofill.AutofillId; import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InlineSuggestionsRequest; import android.view.inputmethod.InputBinding; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnectionInspector; @@ -142,6 +143,7 @@ import com.android.internal.os.TransferPipe; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.view.IInlineSuggestionsRequestCallback; +import com.android.internal.view.IInlineSuggestionsResponseCallback; import com.android.internal.view.IInputContext; import com.android.internal.view.IInputMethod; import com.android.internal.view.IInputMethodClient; @@ -1790,15 +1792,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @GuardedBy("mMethodMap") - private void onCreateInlineSuggestionsRequestLocked(ComponentName componentName, - AutofillId autofillId, IInlineSuggestionsRequestCallback callback) { - + private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId, + ComponentName componentName, AutofillId autofillId, + IInlineSuggestionsRequestCallback callback) { final InputMethodInfo imi = mMethodMap.get(mCurMethodId); try { - if (imi != null && imi.isInlineSuggestionsEnabled() && mCurMethod != null) { + if (userId == mSettings.getCurrentUserId() && imi != null + && imi.isInlineSuggestionsEnabled() && mCurMethod != null) { executeOrSendMessage(mCurMethod, mCaller.obtainMessageOOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod, - componentName, autofillId, callback)); + componentName, autofillId, + new InlineSuggestionsRequestCallbackDecorator(callback, + imi.getPackageName()))); } else { callback.onInlineSuggestionsUnsupported(); } @@ -1808,6 +1813,42 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } /** + * The decorator which validates the host package name in the + * {@link InlineSuggestionsRequest} argument to make sure it matches the IME package name. + */ + private static final class InlineSuggestionsRequestCallbackDecorator + extends IInlineSuggestionsRequestCallback.Stub { + @NonNull + private final IInlineSuggestionsRequestCallback mCallback; + @NonNull + private final String mImePackageName; + + InlineSuggestionsRequestCallbackDecorator( + @NonNull IInlineSuggestionsRequestCallback callback, + @NonNull String imePackageName) { + mCallback = callback; + mImePackageName = imePackageName; + } + + @Override + public void onInlineSuggestionsUnsupported() throws RemoteException { + mCallback.onInlineSuggestionsUnsupported(); + } + + @Override + public void onInlineSuggestionsRequest(InlineSuggestionsRequest request, + IInlineSuggestionsResponseCallback callback) throws RemoteException { + if (!mImePackageName.equals(request.getHostPackageName())) { + throw new SecurityException( + "Host package name in the provide request=[" + request.getHostPackageName() + + "] doesn't match the IME package name=[" + mImePackageName + + "]."); + } + mCallback.onInlineSuggestionsRequest(request, callback); + } + } + + /** * @param imiId if null, returns enabled subtypes for the current imi * @return enabled subtypes of the specified imi */ @@ -4471,10 +4512,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - private void onCreateInlineSuggestionsRequest(ComponentName componentName, - AutofillId autofillId, IInlineSuggestionsRequestCallback callback) { + private void onCreateInlineSuggestionsRequest(@UserIdInt int userId, + ComponentName componentName, AutofillId autofillId, + IInlineSuggestionsRequestCallback callback) { synchronized (mMethodMap) { - onCreateInlineSuggestionsRequestLocked(componentName, autofillId, callback); + onCreateInlineSuggestionsRequestLocked(userId, componentName, autofillId, callback); } } @@ -4542,9 +4584,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @Override - public void onCreateInlineSuggestionsRequest(ComponentName componentName, + public void onCreateInlineSuggestionsRequest(int userId, ComponentName componentName, AutofillId autofillId, IInlineSuggestionsRequestCallback cb) { - mService.onCreateInlineSuggestionsRequest(componentName, autofillId, cb); + mService.onCreateInlineSuggestionsRequest(userId, componentName, autofillId, cb); } @Override diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java index 20d7955e0c77..f09795fbea01 100644 --- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java @@ -191,8 +191,9 @@ public final class MultiClientInputMethodManagerService { } @Override - public void onCreateInlineSuggestionsRequest(ComponentName componentName, - AutofillId autofillId, IInlineSuggestionsRequestCallback cb) { + public void onCreateInlineSuggestionsRequest(int userId, + ComponentName componentName, AutofillId autofillId, + IInlineSuggestionsRequestCallback cb) { try { //TODO(b/137800469): support multi client IMEs. cb.onInlineSuggestionsUnsupported(); diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java index 0d315cd6863d..408c1c9b7d18 100644 --- a/services/core/java/com/android/server/media/MediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java @@ -23,18 +23,22 @@ import android.content.Intent; import android.media.MediaRoute2ProviderInfo; import android.media.RoutingSessionInfo; +import com.android.internal.annotations.GuardedBy; + import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Objects; abstract class MediaRoute2Provider { final ComponentName mComponentName; final String mUniqueId; + final Object mLock = new Object(); Callback mCallback; private volatile MediaRoute2ProviderInfo mProviderInfo; - private volatile List<RoutingSessionInfo> mSessionInfos = Collections.emptyList(); + + @GuardedBy("mLock") + final List<RoutingSessionInfo> mSessionInfos = new ArrayList<>(); MediaRoute2Provider(@NonNull ComponentName componentName) { mComponentName = Objects.requireNonNull(componentName, "Component name must not be null."); @@ -69,11 +73,12 @@ abstract class MediaRoute2Provider { @NonNull public List<RoutingSessionInfo> getSessionInfos() { - return mSessionInfos; + synchronized (mLock) { + return mSessionInfos; + } } - void setProviderState(MediaRoute2ProviderInfo providerInfo, - List<RoutingSessionInfo> sessionInfos) { + void setProviderState(MediaRoute2ProviderInfo providerInfo) { if (providerInfo == null) { mProviderInfo = null; } else { @@ -81,14 +86,6 @@ abstract class MediaRoute2Provider { .setUniqueId(mUniqueId) .build(); } - List<RoutingSessionInfo> sessionInfoWithProviderId = new ArrayList<RoutingSessionInfo>(); - for (RoutingSessionInfo sessionInfo : sessionInfos) { - sessionInfoWithProviderId.add( - new RoutingSessionInfo.Builder(sessionInfo) - .setProviderId(mUniqueId) - .build()); - } - mSessionInfos = sessionInfoWithProviderId; } void notifyProviderState() { @@ -97,9 +94,8 @@ abstract class MediaRoute2Provider { } } - void setAndNotifyProviderState(MediaRoute2ProviderInfo providerInfo, - List<RoutingSessionInfo> sessionInfos) { - setProviderState(providerInfo, sessionInfos); + void setAndNotifyProviderState(MediaRoute2ProviderInfo providerInfo) { + setProviderState(providerInfo); notifyProviderState(); } @@ -112,10 +108,9 @@ abstract class MediaRoute2Provider { void onProviderStateChanged(@Nullable MediaRoute2Provider provider); void onSessionCreated(@NonNull MediaRoute2Provider provider, @Nullable RoutingSessionInfo sessionInfo, long requestId); - // TODO: Remove this when MediaRouter2ServiceImpl notifies clients of session changes. - void onSessionInfoChanged(@NonNull MediaRoute2Provider provider, + void onSessionCreationFailed(@NonNull MediaRoute2Provider provider, long requestId); + void onSessionUpdated(@NonNull MediaRoute2Provider provider, @NonNull RoutingSessionInfo sessionInfo); - // TODO: Call this when service actually notifies of session release. void onSessionReleased(@NonNull MediaRoute2Provider provider, @NonNull RoutingSessionInfo sessionInfo); } diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java index c0ad46f5fa06..3840d0206016 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java @@ -17,7 +17,6 @@ package com.android.server.media; import android.annotation.NonNull; -import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -37,8 +36,6 @@ import android.util.Slog; import java.io.PrintWriter; import java.lang.ref.WeakReference; -import java.util.Collections; -import java.util.List; import java.util.Objects; /** @@ -270,35 +267,69 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv } private void onProviderStateUpdated(Connection connection, - MediaRoute2ProviderInfo providerInfo, List<RoutingSessionInfo> sessionInfos) { + MediaRoute2ProviderInfo providerInfo) { if (mActiveConnection != connection) { return; } if (DEBUG) { Slog.d(TAG, this + ": State changed "); } - setAndNotifyProviderState(providerInfo, sessionInfos); + setAndNotifyProviderState(providerInfo); } - private void onSessionCreated(Connection connection, @Nullable RoutingSessionInfo sessionInfo, + private void onSessionCreated(Connection connection, RoutingSessionInfo sessionInfo, long requestId) { if (mActiveConnection != connection) { return; } - if (sessionInfo != null) { - sessionInfo = new RoutingSessionInfo.Builder(sessionInfo) - .setProviderId(getUniqueId()) - .build(); + + if (sessionInfo == null) { + Slog.w(TAG, "onSessionCreated: Ignoring null sessionInfo sent from " + mComponentName); + return; } + + sessionInfo = new RoutingSessionInfo.Builder(sessionInfo) + .setProviderId(getUniqueId()) + .build(); + + boolean duplicateSessionAlreadyExists = false; + synchronized (mLock) { + for (int i = 0; i < mSessionInfos.size(); i++) { + if (mSessionInfos.get(i).getId().equals(sessionInfo.getId())) { + duplicateSessionAlreadyExists = true; + break; + } + } + mSessionInfos.add(sessionInfo); + } + + if (duplicateSessionAlreadyExists) { + Slog.w(TAG, "onSessionCreated: Duplicate session already exists. Ignoring."); + return; + } + mCallback.onSessionCreated(this, sessionInfo, requestId); } - private void onSessionInfoChanged(Connection connection, RoutingSessionInfo sessionInfo) { + private void onSessionCreationFailed(Connection connection, long requestId) { + if (mActiveConnection != connection) { + return; + } + + if (requestId == MediaRoute2ProviderService.REQUEST_ID_UNKNOWN) { + Slog.w(TAG, "onSessionCreationFailed: Ignoring requestId REQUEST_ID_UNKNOWN"); + return; + } + + mCallback.onSessionCreationFailed(this, requestId); + } + + private void onSessionUpdated(Connection connection, RoutingSessionInfo sessionInfo) { if (mActiveConnection != connection) { return; } if (sessionInfo == null) { - Slog.w(TAG, "onSessionInfoChanged: Ignoring null sessionInfo sent from " + Slog.w(TAG, "onSessionUpdated: Ignoring null sessionInfo sent from " + mComponentName); return; } @@ -307,7 +338,55 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv .setProviderId(getUniqueId()) .build(); - mCallback.onSessionInfoChanged(this, sessionInfo); + boolean found = false; + synchronized (mLock) { + for (int i = 0; i < mSessionInfos.size(); i++) { + if (mSessionInfos.get(i).getId().equals(sessionInfo.getId())) { + mSessionInfos.set(i, sessionInfo); + found = true; + break; + } + } + } + + if (!found) { + Slog.w(TAG, "onSessionUpdated: Matching session info not found"); + return; + } + + mCallback.onSessionUpdated(this, sessionInfo); + } + + private void onSessionReleased(Connection connection, RoutingSessionInfo sessionInfo) { + if (mActiveConnection != connection) { + return; + } + if (sessionInfo == null) { + Slog.w(TAG, "onSessionReleased: Ignoring null sessionInfo sent from " + mComponentName); + return; + } + + sessionInfo = new RoutingSessionInfo.Builder(sessionInfo) + .setProviderId(getUniqueId()) + .build(); + + boolean found = false; + synchronized (mLock) { + for (int i = 0; i < mSessionInfos.size(); i++) { + if (mSessionInfos.get(i).getId().equals(sessionInfo.getId())) { + mSessionInfos.remove(i); + found = true; + break; + } + } + } + + if (!found) { + Slog.w(TAG, "onSessionReleased: Matching session info not found"); + return; + } + + mCallback.onSessionReleased(this, sessionInfo); } private void disconnect() { @@ -315,7 +394,7 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv mConnectionReady = false; mActiveConnection.dispose(); mActiveConnection = null; - setAndNotifyProviderState(null, Collections.emptyList()); + setAndNotifyProviderState(null); } } @@ -421,19 +500,24 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv mHandler.post(() -> onConnectionDied(Connection.this)); } - void postProviderStateUpdated(MediaRoute2ProviderInfo providerInfo, - List<RoutingSessionInfo> sessionInfos) { - mHandler.post(() -> onProviderStateUpdated(Connection.this, - providerInfo, sessionInfos)); + void postProviderStateUpdated(MediaRoute2ProviderInfo providerInfo) { + mHandler.post(() -> onProviderStateUpdated(Connection.this, providerInfo)); } - void postSessionCreated(@Nullable RoutingSessionInfo sessionInfo, long requestId) { - mHandler.post(() -> onSessionCreated(Connection.this, sessionInfo, - requestId)); + void postSessionCreated(RoutingSessionInfo sessionInfo, long requestId) { + mHandler.post(() -> onSessionCreated(Connection.this, sessionInfo, requestId)); } - void postSessionInfoChanged(RoutingSessionInfo sessionInfo) { - mHandler.post(() -> onSessionInfoChanged(Connection.this, sessionInfo)); + void postSessionCreationFailed(long requestId) { + mHandler.post(() -> onSessionCreationFailed(Connection.this, requestId)); + } + + void postSessionUpdated(RoutingSessionInfo sessionInfo) { + mHandler.post(() -> onSessionUpdated(Connection.this, sessionInfo)); + } + + void postSessionReleased(RoutingSessionInfo sessionInfo) { + mHandler.post(() -> onSessionReleased(Connection.this, sessionInfo)); } } @@ -449,16 +533,15 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv } @Override - public void updateState(MediaRoute2ProviderInfo providerInfo, - List<RoutingSessionInfo> sessionInfos) { + public void updateState(MediaRoute2ProviderInfo providerInfo) { Connection connection = mConnectionRef.get(); if (connection != null) { - connection.postProviderStateUpdated(providerInfo, sessionInfos); + connection.postProviderStateUpdated(providerInfo); } } @Override - public void notifySessionCreated(@Nullable RoutingSessionInfo sessionInfo, long requestId) { + public void notifySessionCreated(RoutingSessionInfo sessionInfo, long requestId) { Connection connection = mConnectionRef.get(); if (connection != null) { connection.postSessionCreated(sessionInfo, requestId); @@ -466,10 +549,26 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv } @Override - public void notifySessionInfoChanged(RoutingSessionInfo sessionInfo) { + public void notifySessionCreationFailed(long requestId) { + Connection connection = mConnectionRef.get(); + if (connection != null) { + connection.postSessionCreationFailed(requestId); + } + } + + @Override + public void notifySessionUpdated(RoutingSessionInfo sessionInfo) { + Connection connection = mConnectionRef.get(); + if (connection != null) { + connection.postSessionUpdated(sessionInfo); + } + } + + @Override + public void notifySessionReleased(RoutingSessionInfo sessionInfo) { Connection connection = mConnectionRef.get(); if (connection != null) { - connection.postSessionInfoChanged(sessionInfo); + connection.postSessionReleased(sessionInfo); } } } diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index c48c90db30d1..d940e3587794 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -22,7 +22,6 @@ import static android.media.MediaRouter2Utils.getProviderId; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.ActivityManager; import android.content.Context; import android.content.Intent; @@ -31,6 +30,7 @@ import android.media.IMediaRouter2Client; import android.media.IMediaRouter2Manager; import android.media.MediaRoute2Info; import android.media.MediaRoute2ProviderInfo; +import android.media.MediaRoute2ProviderService; import android.media.RouteDiscoveryPreference; import android.media.RoutingSessionInfo; import android.os.Binder; @@ -876,13 +876,19 @@ class MediaRouter2ServiceImpl { @Override public void onSessionCreated(@NonNull MediaRoute2Provider provider, - @Nullable RoutingSessionInfo sessionInfo, long requestId) { + @NonNull RoutingSessionInfo sessionInfo, long requestId) { sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionCreatedOnHandler, this, provider, sessionInfo, requestId)); } @Override - public void onSessionInfoChanged(@NonNull MediaRoute2Provider provider, + public void onSessionCreationFailed(@NonNull MediaRoute2Provider provider, long requestId) { + sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionCreationFailedOnHandler, + this, provider, requestId)); + } + + @Override + public void onSessionUpdated(@NonNull MediaRoute2Provider provider, @NonNull RoutingSessionInfo sessionInfo) { sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionInfoChangedOnHandler, this, provider, sessionInfo)); @@ -1132,7 +1138,14 @@ class MediaRouter2ServiceImpl { } private void onSessionCreatedOnHandler(@NonNull MediaRoute2Provider provider, - @Nullable RoutingSessionInfo sessionInfo, long requestId) { + @NonNull RoutingSessionInfo sessionInfo, long requestId) { + + if (requestId == MediaRoute2ProviderService.REQUEST_ID_UNKNOWN) { + // The session is created without any matching request. + // TODO: Tell managers for the session creation + return; + } + SessionCreationRequest matchingRequest = null; for (SessionCreationRequest request : mSessionCreationRequests) { @@ -1182,6 +1195,30 @@ class MediaRouter2ServiceImpl { // TODO: Tell managers for the session creation } + private void onSessionCreationFailedOnHandler(@NonNull MediaRoute2Provider provider, + long requestId) { + SessionCreationRequest matchingRequest = null; + + for (SessionCreationRequest request : mSessionCreationRequests) { + if (request.mRequestId == requestId + && TextUtils.equals( + request.mRoute.getProviderId(), provider.getUniqueId())) { + matchingRequest = request; + break; + } + } + + if (matchingRequest == null) { + Slog.w(TAG, "Ignoring session creation failed result for unknown request. " + + "requestId=" + requestId); + return; + } + + mSessionCreationRequests.remove(matchingRequest); + notifySessionCreationFailed(matchingRequest.mClientRecord, + toClientRequestId(requestId)); + } + private void onSessionInfoChangedOnHandler(@NonNull MediaRoute2Provider provider, @NonNull RoutingSessionInfo sessionInfo) { diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java index 961d3d01a67d..6695227fd236 100644 --- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java @@ -169,7 +169,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { for (MediaRoute2Info route : mBluetoothRoutes) { builder.addRoute(route); } - setProviderState(builder.build(), Collections.emptyList()); + setProviderState(builder.build()); mHandler.post(() -> notifyProviderState()); } @@ -212,6 +212,6 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { for (MediaRoute2Info route : mBluetoothRoutes) { builder.addRoute(route); } - setAndNotifyProviderState(builder.build(), Collections.emptyList()); + setAndNotifyProviderState(builder.build()); } } diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java index ffcd6cf8603c..bcfe5773cfa4 100644 --- a/services/core/java/com/android/server/pm/InstantAppRegistry.java +++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java @@ -338,9 +338,8 @@ class InstantAppRegistry { } @GuardedBy("mService.mLock") - public void onPackageUninstalledLPw(@NonNull AndroidPackage pkg, + public void onPackageUninstalledLPw(@NonNull AndroidPackage pkg, @Nullable PackageSetting ps, @NonNull int[] userIds) { - PackageSetting ps = mService.getPackageSetting(pkg.getPackageName()); if (ps == null) { return; } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index dad32cd6c83e..159b4e49bfea 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -17502,7 +17502,8 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { if (res) { if (pkg != null) { - mInstantAppRegistry.onPackageUninstalledLPw(pkg, info.removedUsers); + mInstantAppRegistry.onPackageUninstalledLPw(pkg, uninstalledPs, + info.removedUsers); } updateSequenceNumberLP(uninstalledPs, info.removedUsers); updateInstantAppInstallerLocked(packageName); diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java index 52714933c8e2..6daf5162ebad 100644 --- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java +++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java @@ -743,8 +743,8 @@ class LegacyGlobalActions implements DialogInterface.OnDismissListener, DialogIn } else if (TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) { // Airplane mode can be changed after ECM exits if airplane toggle button // is pressed during ECM mode - if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) && - mIsWaitingForEcmExit) { + if (!(intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)) + && mIsWaitingForEcmExit) { mIsWaitingForEcmExit = false; changeAirplaneModeSystemSetting(true); } diff --git a/services/core/java/com/android/server/stats/StatsPullAtomService.java b/services/core/java/com/android/server/stats/StatsPullAtomService.java index a75f1c210bc0..5ee7eff20e24 100644 --- a/services/core/java/com/android/server/stats/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/StatsPullAtomService.java @@ -186,6 +186,12 @@ public class StatsPullAtomService extends SystemService { private static final String TAG = "StatsPullAtomService"; private static final boolean DEBUG = true; + private static final String RESULT_RECEIVER_CONTROLLER_KEY = "controller_activity"; + /** + * How long to wait on an individual subsystem to return its stats. + */ + private static final long EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS = 2000; + private final Object mNetworkStatsLock = new Object(); @GuardedBy("mNetworkStatsLock") private INetworkStatsService mNetworkStatsService; @@ -327,11 +333,12 @@ public class StatsPullAtomService extends SystemService { } private void registerWifiBytesTransfer() { int tagId = StatsLog.WIFI_BYTES_TRANSFER; - PullAtomMetadata metaData = PullAtomMetadata.newBuilder() - .setAdditiveFields(new int[] {2, 3, 4, 5}).build(); + PullAtomMetadata metadata = PullAtomMetadata.newBuilder() + .setAdditiveFields(new int[] {2, 3, 4, 5}) + .build(); mStatsManager.registerPullAtomCallback( tagId, - metaData, + metadata, (atomTag, data) -> pullWifiBytesTransfer(atomTag, data), Executors.newSingleThreadExecutor() ); @@ -356,6 +363,7 @@ public class StatsPullAtomService extends SystemService { addNetworkStats(atomTag, pulledData, stats, false); } catch (RemoteException e) { Slog.e(TAG, "Pulling netstats for wifi bytes has error", e); + return StatsManager.PULL_SKIP; } finally { Binder.restoreCallingIdentity(token); } @@ -382,36 +390,224 @@ public class StatsPullAtomService extends SystemService { } } + /** + * Allows rollups per UID but keeping the set (foreground/background) slicing. + * Adapted from groupedByUid in frameworks/base/core/java/android/net/NetworkStats.java + */ + private NetworkStats rollupNetworkStatsByFGBG(NetworkStats stats) { + final NetworkStats ret = new NetworkStats(stats.getElapsedRealtime(), 1); + + final NetworkStats.Entry entry = new NetworkStats.Entry(); + entry.iface = NetworkStats.IFACE_ALL; + entry.tag = NetworkStats.TAG_NONE; + entry.metered = NetworkStats.METERED_ALL; + entry.roaming = NetworkStats.ROAMING_ALL; + + int size = stats.size(); + NetworkStats.Entry recycle = new NetworkStats.Entry(); // Used for retrieving values + for (int i = 0; i < size; i++) { + stats.getValues(i, recycle); + + // Skip specific tags, since already counted in TAG_NONE + if (recycle.tag != NetworkStats.TAG_NONE) continue; + + entry.set = recycle.set; // Allows slicing by background/foreground + entry.uid = recycle.uid; + entry.rxBytes = recycle.rxBytes; + entry.rxPackets = recycle.rxPackets; + entry.txBytes = recycle.txBytes; + entry.txPackets = recycle.txPackets; + // Operations purposefully omitted since we don't use them for statsd. + ret.combineValues(entry); + } + return ret; + } + private void registerWifiBytesTransferBackground() { - // No op. + int tagId = StatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG; + PullAtomMetadata metadata = PullAtomMetadata.newBuilder() + .setAdditiveFields(new int[] {3, 4, 5, 6}) + .build(); + mStatsManager.registerPullAtomCallback( + tagId, + metadata, + (atomTag, data) -> pullWifiBytesTransferBackground(atomTag, data), + Executors.newSingleThreadExecutor() + ); } - private void pullWifiBytesTransferBackground() { - // No op. + private int pullWifiBytesTransferBackground(int atomTag, List<StatsEvent> pulledData) { + INetworkStatsService networkStatsService = getINetworkStatsService(); + if (networkStatsService == null) { + Slog.e(TAG, "NetworkStats Service is not available!"); + return StatsManager.PULL_SKIP; + } + long token = Binder.clearCallingIdentity(); + try { + BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); + String[] ifaces = bs.getWifiIfaces(); + if (ifaces.length == 0) { + return StatsManager.PULL_SKIP; + } + NetworkStats stats = rollupNetworkStatsByFGBG( + networkStatsService.getDetailedUidStats(ifaces)); + addNetworkStats(atomTag, pulledData, stats, true); + } catch (RemoteException e) { + Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e); + return StatsManager.PULL_SKIP; + } finally { + Binder.restoreCallingIdentity(token); + } + return StatsManager.PULL_SUCCESS; } private void registerMobileBytesTransfer() { - // No op. + int tagId = StatsLog.MOBILE_BYTES_TRANSFER; + PullAtomMetadata metadata = PullAtomMetadata.newBuilder() + .setAdditiveFields(new int[] {2, 3, 4, 5}) + .build(); + mStatsManager.registerPullAtomCallback( + tagId, + metadata, + (atomTag, data) -> pullMobileBytesTransfer(atomTag, data), + Executors.newSingleThreadExecutor() + ); } - private void pullMobileBytesTransfer() { - // No op. + private int pullMobileBytesTransfer(int atomTag, List<StatsEvent> pulledData) { + INetworkStatsService networkStatsService = getINetworkStatsService(); + if (networkStatsService == null) { + Slog.e(TAG, "NetworkStats Service is not available!"); + return StatsManager.PULL_SKIP; + } + long token = Binder.clearCallingIdentity(); + try { + BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); + String[] ifaces = bs.getMobileIfaces(); + if (ifaces.length == 0) { + return StatsManager.PULL_SKIP; + } + // Combine all the metrics per Uid into one record. + NetworkStats stats = networkStatsService.getDetailedUidStats(ifaces).groupedByUid(); + addNetworkStats(atomTag, pulledData, stats, false); + } catch (RemoteException e) { + Slog.e(TAG, "Pulling netstats for mobile bytes has error", e); + return StatsManager.PULL_SKIP; + } finally { + Binder.restoreCallingIdentity(token); + } + return StatsManager.PULL_SUCCESS; } private void registerMobileBytesTransferBackground() { - // No op. + int tagId = StatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG; + PullAtomMetadata metadata = PullAtomMetadata.newBuilder() + .setAdditiveFields(new int[] {3, 4, 5, 6}) + .build(); + mStatsManager.registerPullAtomCallback( + tagId, + metadata, + (atomTag, data) -> pullMobileBytesTransferBackground(atomTag, data), + Executors.newSingleThreadExecutor() + ); } - private void pullMobileBytesTransferBackground() { - // No op. + private int pullMobileBytesTransferBackground(int atomTag, List<StatsEvent> pulledData) { + INetworkStatsService networkStatsService = getINetworkStatsService(); + if (networkStatsService == null) { + Slog.e(TAG, "NetworkStats Service is not available!"); + return StatsManager.PULL_SKIP; + } + long token = Binder.clearCallingIdentity(); + try { + BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); + String[] ifaces = bs.getMobileIfaces(); + if (ifaces.length == 0) { + return StatsManager.PULL_SKIP; + } + NetworkStats stats = rollupNetworkStatsByFGBG( + networkStatsService.getDetailedUidStats(ifaces)); + addNetworkStats(atomTag, pulledData, stats, true); + } catch (RemoteException e) { + Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e); + return StatsManager.PULL_SKIP; + } finally { + Binder.restoreCallingIdentity(token); + } + return StatsManager.PULL_SUCCESS; } private void registerBluetoothBytesTransfer() { - // No op. + int tagId = StatsLog.BLUETOOTH_BYTES_TRANSFER; + PullAtomMetadata metadata = PullAtomMetadata.newBuilder() + .setAdditiveFields(new int[] {2, 3}) + .build(); + mStatsManager.registerPullAtomCallback( + tagId, + metadata, + (atomTag, data) -> pullBluetoothBytesTransfer(atomTag, data), + Executors.newSingleThreadExecutor() + ); } - private void pullBluetoothBytesTransfer() { - // No op. + /** + * Helper method to extract the Parcelable controller info from a + * SynchronousResultReceiver. + */ + private static <T extends Parcelable> T awaitControllerInfo( + @Nullable SynchronousResultReceiver receiver) { + if (receiver == null) { + return null; + } + + try { + final SynchronousResultReceiver.Result result = + receiver.awaitResult(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS); + if (result.bundle != null) { + // This is the final destination for the Bundle. + result.bundle.setDefusable(true); + + final T data = result.bundle.getParcelable(RESULT_RECEIVER_CONTROLLER_KEY); + if (data != null) { + return data; + } + } + Slog.e(TAG, "no controller energy info supplied for " + receiver.getName()); + } catch (TimeoutException e) { + Slog.w(TAG, "timeout reading " + receiver.getName() + " stats"); + } + return null; + } + + private synchronized BluetoothActivityEnergyInfo fetchBluetoothData() { + // TODO: Investigate whether the synchronized keyword is needed. + final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + if (adapter != null) { + SynchronousResultReceiver bluetoothReceiver = new SynchronousResultReceiver( + "bluetooth"); + adapter.requestControllerActivityEnergyInfo(bluetoothReceiver); + return awaitControllerInfo(bluetoothReceiver); + } else { + Slog.e(TAG, "Failed to get bluetooth adapter!"); + return null; + } + } + + private int pullBluetoothBytesTransfer(int atomTag, List<StatsEvent> pulledData) { + BluetoothActivityEnergyInfo info = fetchBluetoothData(); + if (info == null || info.getUidTraffic() == null) { + return StatsManager.PULL_SKIP; + } + for (UidTraffic traffic : info.getUidTraffic()) { + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeInt(traffic.getUid()) + .writeLong(traffic.getRxBytes()) + .writeLong(traffic.getTxBytes()) + .build(); + pulledData.add(e); + } + return StatsManager.PULL_SUCCESS; } private void registerKernelWakelock() { @@ -479,11 +675,31 @@ public class StatsPullAtomService extends SystemService { } private void registerBluetoothActivityInfo() { - // No op. + int tagId = StatsLog.BLUETOOTH_ACTIVITY_INFO; + mStatsManager.registerPullAtomCallback( + tagId, + /* metadata */ null, + (atomTag, data) -> pullBluetoothActivityInfo(atomTag, data), + Executors.newSingleThreadExecutor() + ); } - private void pullBluetoothActivityInfo() { - // No op. + private int pullBluetoothActivityInfo(int atomTag, List<StatsEvent> pulledData) { + BluetoothActivityEnergyInfo info = fetchBluetoothData(); + if (info == null) { + return StatsManager.PULL_SKIP; + } + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeLong(info.getTimeStamp()) + .writeInt(info.getBluetoothStackState()) + .writeLong(info.getControllerTxTimeMillis()) + .writeLong(info.getControllerRxTimeMillis()) + .writeLong(info.getControllerIdleTimeMillis()) + .writeLong(info.getControllerEnergyUsed()) + .build(); + pulledData.add(e); + return StatsManager.PULL_SUCCESS; } private void registerSystemElapsedRealtime() { @@ -695,11 +911,26 @@ public class StatsPullAtomService extends SystemService { } private void registerPowerProfile() { - // No op. + int tagId = StatsLog.POWER_PROFILE; + mStatsManager.registerPullAtomCallback( + tagId, + /* PullAtomMetadata */ null, + (atomTag, data) -> pullPowerProfile(atomTag, data), + Executors.newSingleThreadExecutor() + ); } - private void pullPowerProfile() { - // No op. + private int pullPowerProfile(int atomTag, List<StatsEvent> pulledData) { + PowerProfile powerProfile = new PowerProfile(mContext); + ProtoOutputStream proto = new ProtoOutputStream(); + powerProfile.dumpDebug(proto); + proto.flush(); + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeByteArray(proto.getBytes()) + .build(); + pulledData.add(e); + return StatsManager.PULL_SUCCESS; } private void registerProcessCpuTime() { diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp index 4696dd0bb88b..0275f3ea32f7 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp @@ -33,7 +33,6 @@ #include "bpf/BpfUtils.h" #include "netdbpf/BpfNetworkStats.h" -using android::bpf::Stats; using android::bpf::bpfGetUidStats; using android::bpf::bpfGetIfaceStats; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 6b81fdd2d270..485899ef05e3 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -23,7 +23,6 @@ import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER; import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY; -import static android.app.admin.DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED; import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE; import static android.app.admin.DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED; import static android.app.admin.DevicePolicyManager.CODE_HAS_DEVICE_OWNER; @@ -4118,6 +4117,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER, userHandle)) { mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false, userHandle); } + // When a device owner is set, the system automatically restricts adding a managed profile. + // Remove this restriction when the device owner is cleared. + if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, userHandle)) { + mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, false, + userHandle); + } } /** @@ -8056,10 +8061,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { updateDeviceOwnerLocked(); setDeviceOwnerSystemPropertyLocked(); - // TODO Send to system too? - mInjector.binderWithCleanCallingIdentity( - () -> sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED, - userId)); + mInjector.binderWithCleanCallingIdentity(() -> { + // Restrict adding a managed profile when a device owner is set on the device. + // That is to prevent the co-existence of a managed profile and a device owner + // on the same device. + // Instead, the device may be provisioned with an organization-owned managed + // profile, such that the admin on that managed profile has extended management + // capabilities that can affect the entire device (but not access private data + // on the primary profile). + mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true, + UserHandle.of(userId)); + // TODO Send to system too? + sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED, userId); + }); mDeviceAdminServiceController.startServiceForOwner( admin.getPackageName(), userId, "set-device-owner"); @@ -8322,6 +8336,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { throw new IllegalArgumentException("Not active admin: " + who); } + final int parentUserId = getProfileParentId(userHandle); + // When trying to set a profile owner on a new user, it may be that this user is + // a profile - but it may not be a managed profile if there's a restriction on the + // parent to add managed profiles (e.g. if the device has a device owner). + if (parentUserId != userHandle && mUserManager.hasUserRestriction( + UserManager.DISALLOW_ADD_MANAGED_PROFILE, + UserHandle.of(parentUserId))) { + Slog.i(LOG_TAG, "Cannot set profile owner because of restriction."); + return false; + } + if (isAdb()) { // Log profile owner provisioning was started using adb. MetricsLogger.action(mContext, PROVISIONING_ENTRY_POINT_ADB, LOG_TAG_PROFILE_OWNER); @@ -12387,25 +12412,41 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final long ident = mInjector.binderClearCallingIdentity(); try { final UserHandle callingUserHandle = UserHandle.of(callingUserId); - final ComponentName ownerAdmin = getOwnerComponent(packageName, callingUserId); - if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, - callingUserHandle)) { - // An admin can initiate provisioning if it has set the restriction. - if (ownerAdmin == null || isAdminAffectedByRestriction(ownerAdmin, - UserManager.DISALLOW_ADD_MANAGED_PROFILE, callingUserId)) { - return CODE_ADD_MANAGED_PROFILE_DISALLOWED; - } - } - boolean canRemoveProfile = true; - if (mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, - callingUserHandle)) { - // We can remove a profile if the admin itself has set the restriction. - if (ownerAdmin == null || isAdminAffectedByRestriction(ownerAdmin, - UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, - callingUserId)) { - canRemoveProfile = false; - } + final boolean hasDeviceOwner; + synchronized (getLockObject()) { + hasDeviceOwner = getDeviceOwnerAdminLocked() != null; + } + + final boolean addingProfileRestricted = mUserManager.hasUserRestriction( + UserManager.DISALLOW_ADD_MANAGED_PROFILE, callingUserHandle); + + UserInfo parentUser = mUserManager.getProfileParent(callingUserId); + final boolean addingProfileRestrictedOnParent = (parentUser != null) + && mUserManager.hasUserRestriction( + UserManager.DISALLOW_ADD_MANAGED_PROFILE, + UserHandle.of(parentUser.id)); + + Slog.i(LOG_TAG, String.format( + "When checking for managed profile provisioning: Has device owner? %b, adding" + + " profile restricted? %b, adding profile restricted on parent? %b", + hasDeviceOwner, addingProfileRestricted, addingProfileRestrictedOnParent)); + + // If there's a device owner, the restriction on adding a managed profile must be set + // somewhere. + if (hasDeviceOwner && !addingProfileRestricted && !addingProfileRestrictedOnParent) { + Slog.wtf(LOG_TAG, "Has a device owner but no restriction on adding a profile."); + } + + // Do not allow adding a managed profile if there's a restriction, either on the current + // user or its parent user. + if (addingProfileRestricted || addingProfileRestrictedOnParent) { + return CODE_CANNOT_ADD_MANAGED_PROFILE; } + // If there's a restriction on removing the managed profile then we have to take it + // into account when checking whether more profiles can be added. + boolean canRemoveProfile = + !mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, + callingUserHandle); if (!mUserManager.canAddMoreManagedProfiles(callingUserId, canRemoveProfile)) { return CODE_CANNOT_ADD_MANAGED_PROFILE; } diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java index 2fb2021de200..e609adc2a067 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java @@ -16,7 +16,7 @@ package com.android.server; -import static android.net.NetworkScoreManager.CACHE_FILTER_NONE; +import static android.net.NetworkScoreManager.SCORE_FILTER_NONE; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -306,7 +306,7 @@ public class NetworkScoreServiceTest { bindToScorer(true /*callerIsScorer*/); mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, - mNetworkScoreCache, CACHE_FILTER_NONE); + mNetworkScoreCache, SCORE_FILTER_NONE); mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); @@ -321,9 +321,9 @@ public class NetworkScoreServiceTest { bindToScorer(true /*callerIsScorer*/); mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, - mNetworkScoreCache, CACHE_FILTER_NONE); + mNetworkScoreCache, SCORE_FILTER_NONE); mNetworkScoreService.registerNetworkScoreCache( - NetworkKey.TYPE_WIFI, mNetworkScoreCache2, CACHE_FILTER_NONE); + NetworkKey.TYPE_WIFI, mNetworkScoreCache2, SCORE_FILTER_NONE); // updateScores should update both caches mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); @@ -378,7 +378,7 @@ public class NetworkScoreServiceTest { bindToScorer(true /*callerIsScorer*/); mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache, - CACHE_FILTER_NONE); + SCORE_FILTER_NONE); mNetworkScoreService.clearScores(); verify(mNetworkScoreCache).clearScores(); @@ -392,7 +392,7 @@ public class NetworkScoreServiceTest { .thenReturn(PackageManager.PERMISSION_GRANTED); mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache, - CACHE_FILTER_NONE); + SCORE_FILTER_NONE); mNetworkScoreService.clearScores(); verify(mNetworkScoreCache).clearScores(); @@ -472,7 +472,7 @@ public class NetworkScoreServiceTest { try { mNetworkScoreService.registerNetworkScoreCache( - NetworkKey.TYPE_WIFI, mNetworkScoreCache, CACHE_FILTER_NONE); + NetworkKey.TYPE_WIFI, mNetworkScoreCache, SCORE_FILTER_NONE); fail("SecurityException expected"); } catch (SecurityException e) { // expected @@ -615,7 +615,7 @@ public class NetworkScoreServiceTest { new ArrayList<>(scoredNetworkList), NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter); - consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE); + consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_NONE); verify(mNetworkScoreCache).updateScores(scoredNetworkList); verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter); @@ -656,7 +656,7 @@ public class NetworkScoreServiceTest { Collections.emptyList(), NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter); - consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE); + consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_NONE); verifyZeroInteractions(mNetworkScoreCache, mCurrentNetworkFilter, mScanResultsFilter); } @@ -673,7 +673,7 @@ public class NetworkScoreServiceTest { List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList); filteredList.remove(SCORED_NETWORK); when(mCurrentNetworkFilter.apply(scoredNetworkList)).thenReturn(filteredList); - consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK); + consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_CURRENT_NETWORK); verify(mNetworkScoreCache).updateScores(filteredList); verifyZeroInteractions(mScanResultsFilter); @@ -691,7 +691,7 @@ public class NetworkScoreServiceTest { List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList); filteredList.remove(SCORED_NETWORK); when(mScanResultsFilter.apply(scoredNetworkList)).thenReturn(filteredList); - consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS); + consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_SCAN_RESULTS); verify(mNetworkScoreCache).updateScores(filteredList); verifyZeroInteractions(mCurrentNetworkFilter); diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java index 0f11566f512c..39a3aae767ea 100644 --- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java @@ -212,7 +212,8 @@ public class AccountManagerServiceTest extends AndroidTestCase { String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE}; when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list); - Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName()); + Account[] accounts = mAms.getAccountsAsUser(null, + UserHandle.getCallingUserId(), mContext.getOpPackageName()); Arrays.sort(accounts, new AccountSorter()); assertEquals(6, accounts.length); assertEquals(a11, accounts[0]); @@ -222,8 +223,8 @@ public class AccountManagerServiceTest extends AndroidTestCase { assertEquals(a22, accounts[4]); assertEquals(a32, accounts[5]); - accounts = mAms.getAccounts(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, - mContext.getOpPackageName()); + accounts = mAms.getAccountsAsUser(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, + UserHandle.getCallingUserId(), mContext.getOpPackageName()); Arrays.sort(accounts, new AccountSorter()); assertEquals(3, accounts.length); assertEquals(a11, accounts[0]); @@ -232,8 +233,8 @@ public class AccountManagerServiceTest extends AndroidTestCase { mAms.removeAccountInternal(a21); - accounts = mAms.getAccounts(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, - mContext.getOpPackageName()); + accounts = mAms.getAccountsAsUser(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, + UserHandle.getCallingUserId(), mContext.getOpPackageName()); Arrays.sort(accounts, new AccountSorter()); assertEquals(2, accounts.length); assertEquals(a11, accounts[0]); @@ -373,7 +374,8 @@ public class AccountManagerServiceTest extends AndroidTestCase { unlockSystemUser(); String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE}; when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list); - Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName()); + Account[] accounts = mAms.getAccountsAsUser(null, UserHandle.getCallingUserId(), + mContext.getOpPackageName()); assertEquals("1 account should be migrated", 1, accounts.length); assertEquals(PreNTestDatabaseHelper.ACCOUNT_NAME, accounts[0].name); assertEquals(PreNTestDatabaseHelper.ACCOUNT_PASSWORD, mAms.getPassword(accounts[0])); @@ -2980,7 +2982,8 @@ public class AccountManagerServiceTest extends AndroidTestCase { Log.d(TAG, logPrefix + " getAccounts started"); long ti = System.currentTimeMillis(); try { - Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName()); + Account[] accounts = mAms.getAccountsAsUser(null, + UserHandle.getCallingUserId(), mContext.getOpPackageName()); if (accounts == null || accounts.length != 1 || !AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1.equals( accounts[0].type)) { @@ -3051,7 +3054,8 @@ public class AccountManagerServiceTest extends AndroidTestCase { Log.d(TAG, logPrefix + " getAccounts started"); long ti = System.currentTimeMillis(); try { - Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName()); + Account[] accounts = mAms.getAccountsAsUser(null, + UserHandle.getCallingUserId(), mContext.getOpPackageName()); if (accounts == null || accounts.length != 1 || !AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1.equals( accounts[0].type)) { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 21034d3de9b4..45729e5fd41f 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -34,6 +34,7 @@ import static com.android.server.testutils.TestUtils.assertExpectException; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyObject; @@ -275,6 +276,29 @@ public class DevicePolicyManagerTest extends DpmTestBase { }).when(getServices().userManager).getApplicationRestrictions( anyString(), any(UserHandle.class)); + // Emulate UserManager.setUserRestriction/getUserRestrictions + final Map<UserHandle, Bundle> userRestrictions = new HashMap<>(); + + doAnswer((Answer<Void>) invocation -> { + String key = (String) invocation.getArguments()[0]; + boolean value = (Boolean) invocation.getArguments()[1]; + UserHandle user = (UserHandle) invocation.getArguments()[2]; + Bundle userBundle = userRestrictions.getOrDefault(user, new Bundle()); + userBundle.putBoolean(key, value); + + userRestrictions.put(user, userBundle); + return null; + }).when(getServices().userManager).setUserRestriction( + anyString(), anyBoolean(), any(UserHandle.class)); + + doAnswer((Answer<Boolean>) invocation -> { + String key = (String) invocation.getArguments()[0]; + UserHandle user = (UserHandle) invocation.getArguments()[1]; + Bundle userBundle = userRestrictions.getOrDefault(user, new Bundle()); + return userBundle.getBoolean(key); + }).when(getServices().userManager).hasUserRestriction( + anyString(), any(UserHandle.class)); + // Add the first secondary user. getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0, UserManager.USER_TYPE_FULL_SECONDARY); @@ -822,10 +846,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID); - // Setup device owner. mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; mContext.packageName = admin1.getPackageName(); - setupDeviceOwner(); // Add a managed profile belonging to the system user. addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); @@ -833,18 +855,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Change the parent user's password. dpm.reportPasswordChanged(UserHandle.USER_SYSTEM); - // Both the device owner and the managed profile owner should receive this broadcast. + // The managed profile owner should receive this broadcast. final Intent intent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED); intent.setComponent(admin1); intent.putExtra(Intent.EXTRA_USER, UserHandle.of(UserHandle.USER_SYSTEM)); verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( MockUtils.checkIntent(intent), - MockUtils.checkUserHandle(UserHandle.USER_SYSTEM), - eq(null), - any(Bundle.class)); - verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( - MockUtils.checkIntent(intent), MockUtils.checkUserHandle(MANAGED_PROFILE_USER_ID), eq(null), any(Bundle.class)); @@ -864,12 +881,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID); - // Setup device owner. + // Configure system as having separate profile challenge. mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; mContext.packageName = admin1.getPackageName(); doReturn(true).when(getServices().lockPatternUtils) .isSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID); - setupDeviceOwner(); // Add a managed profile belonging to the system user. addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); @@ -954,6 +970,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().iactivityManager, times(1)).updateDeviceOwner( eq(admin1.getPackageName())); + verify(getServices().userManager, times(1)).setUserRestriction( + eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE), + eq(true), eq(UserHandle.SYSTEM)); + verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED), MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)); @@ -2005,12 +2025,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertNoDeviceOwnerRestrictions(); - // Initialize DPMS again and check that the user restriction wasn't enabled again. reset(getServices().userManagerInternal); - initializeDpms(); - assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName())); - assertNotNull(dpms.getDeviceOwnerAdminLocked()); + // Ensure the DISALLOW_REMOVE_MANAGED_PROFILES restriction doesn't show up as a + // restriction to the device owner. + dpm.addUserRestriction(admin1, UserManager.DISALLOW_REMOVE_MANAGED_PROFILE); assertNoDeviceOwnerRestrictions(); } @@ -3106,7 +3125,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { setup_nonSplitUser_withDo_primaryUser(); final int MANAGED_PROFILE_USER_ID = 18; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 1308); - addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, false /* we can't remove a managed profile */)).thenReturn(false); when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, @@ -3158,41 +3176,16 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, false); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE, false); - // COMP mode is allowed. + // COMP mode NOT is allowed. assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, - DevicePolicyManager.CODE_OK); - assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); + DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); + assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); - // And other DPCs can also provision a managed profile (DO + BYOD case). + // And other DPCs can NOT provision a managed profile. assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DpmMockContext.ANOTHER_PACKAGE_NAME, - DevicePolicyManager.CODE_OK); - assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true, - DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID); - } - - public void testProvisioning_nonSplitUser_withDo_primaryUser_restrictedByDo() throws Exception { - setup_nonSplitUser_withDo_primaryUser(); - mContext.packageName = admin1.getPackageName(); - mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); - // The DO should be allowed to initiate provisioning if it set the restriction itself, but - // other packages should be forbidden. - when(getServices().userManager.hasUserRestriction( - eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE), - eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid)))) - .thenReturn(true); - when(getServices().userManager.getUserRestrictionSource( - eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE), - eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid)))) - .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER); - assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, - DevicePolicyManager.CODE_OK); - assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); - assertCheckProvisioningPreCondition( - DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, - DpmMockContext.ANOTHER_PACKAGE_NAME, - DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED); + DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false, DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID); } @@ -3213,31 +3206,46 @@ public class DevicePolicyManagerTest extends DpmTestBase { eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid)))) .thenReturn(UserManager.RESTRICTION_SOURCE_SYSTEM); assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, - DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED); + DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DpmMockContext.ANOTHER_PACKAGE_NAME, - DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED); + DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false, DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID); } - public void testCheckProvisioningPreCondition_nonSplitUser_comp() throws Exception { + public void testCheckCannotSetProfileOwnerWithDeviceOwner() throws Exception { + setup_nonSplitUser_withDo_primaryUser(); + final int managedProfileUserId = 18; + final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 1308); + + final int userId = UserHandle.getUserId(managedProfileAdminUid); + getServices().addUser(userId, 0, UserManager.USER_TYPE_PROFILE_MANAGED, + UserHandle.USER_SYSTEM); + mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS); + setUpPackageManagerForFakeAdmin(admin1, managedProfileAdminUid, admin1); + dpm.setActiveAdmin(admin1, false, userId); + assertFalse(dpm.setProfileOwner(admin1, null, userId)); + mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS); + } + + public void testCheckProvisioningPreCondition_nonSplitUser_attemptingComp() throws Exception { setup_nonSplitUser_withDo_primaryUser_ManagedProfile(); mContext.packageName = admin1.getPackageName(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); // We can delete the managed profile to create a new one, so provisioning is allowed. assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, - DevicePolicyManager.CODE_OK); - assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); + DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); + assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); assertCheckProvisioningPreCondition( DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, DpmMockContext.ANOTHER_PACKAGE_NAME, - DevicePolicyManager.CODE_OK); - assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true, + DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); + assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false, DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID); } @@ -3265,8 +3273,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { // But the device owner can still do it because it has set the restriction itself. assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, - DevicePolicyManager.CODE_OK); - assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); + DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); + assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); } private void setup_splitUser_firstBoot_systemUser() throws Exception { @@ -3475,6 +3483,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) .thenReturn(true); when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true); + when(getServices().userManager.getProfileParent(DpmMockContext.CALLER_USER_HANDLE)) + .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); when(getServices().userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE, true)).thenReturn(true); setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE); @@ -3487,7 +3497,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { setup_provisionManagedProfileWithDeviceOwner_primaryUser(); setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid); mContext.packageName = admin1.getPackageName(); - assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true); + assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); } public void testCheckProvisioningPreCondition_provisionManagedProfileWithDeviceOwner_primaryUser() @@ -3495,9 +3505,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { setup_provisionManagedProfileWithDeviceOwner_primaryUser(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); - // COMP mode is allowed. + // COMP mode is NOT allowed. assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, - DevicePolicyManager.CODE_OK); + DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); } private void setup_provisionManagedProfileCantRemoveUser_primaryUser() throws Exception { @@ -4014,11 +4024,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); MoreAsserts.assertEmpty(targetUsers); - // Setup a managed profile managed by the same admin. - final int MANAGED_PROFILE_USER_ID = 15; - final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456); - addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); - // Add a secondary user, it should never talk with. final int ANOTHER_USER_ID = 36; getServices().addUser(ANOTHER_USER_ID, 0, UserManager.USER_TYPE_FULL_SECONDARY); @@ -4028,30 +4033,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); MoreAsserts.assertEmpty(targetUsers); - mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); - MoreAsserts.assertEmpty(targetUsers); - // Setting affiliation ids final Set<String> userAffiliationIds = Collections.singleton("some.affiliation-id"); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; dpm.setAffiliationIds(admin1, userAffiliationIds); - mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - dpm.setAffiliationIds(admin1, userAffiliationIds); - - // Calling from device owner admin, the result list should just contain the managed - // profile user id. - mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; - targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); - MoreAsserts.assertContentsInAnyOrder(targetUsers, UserHandle.of(MANAGED_PROFILE_USER_ID)); - - // Calling from managed profile admin, the result list should just contain the system - // user id. - mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); - MoreAsserts.assertContentsInAnyOrder(targetUsers, UserHandle.SYSTEM); - // Changing affiliation ids in one dpm.setAffiliationIds(admin1, Collections.singleton("some-different-affiliation-id")); @@ -4065,38 +4051,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { MoreAsserts.assertEmpty(targetUsers); } - public void testGetBindDeviceAdminTargetUsers_differentPackage() throws Exception { - // Setup a device owner. - mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; - setupDeviceOwner(); - - // Set up a managed profile managed by different package. - final int MANAGED_PROFILE_USER_ID = 15; - final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456); - final ComponentName adminDifferentPackage = - new ComponentName("another.package", "whatever.class"); - addManagedProfile(adminDifferentPackage, MANAGED_PROFILE_ADMIN_UID, admin2); - - // Setting affiliation ids - final Set<String> userAffiliationIds = Collections.singleton("some-affiliation-id"); - dpm.setAffiliationIds(admin1, userAffiliationIds); - - mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - dpm.setAffiliationIds(adminDifferentPackage, userAffiliationIds); - - // Calling from device owner admin, we should get zero bind device admin target users as - // their packages are different. - mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; - List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1); - MoreAsserts.assertEmpty(targetUsers); - - // Calling from managed profile admin, we should still get zero target users for the same - // reason. - mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - targetUsers = dpm.getBindDeviceAdminTargetUsers(adminDifferentPackage); - MoreAsserts.assertEmpty(targetUsers); - } - private void verifyLockTaskState(int userId) throws Exception { verifyLockTaskState(userId, new String[0], DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS); @@ -4133,79 +4087,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { () -> dpm.setLockTaskFeatures(who, flags)); } - public void testLockTaskPolicyAllowedForAffiliatedUsers() throws Exception { - // Setup a device owner. - mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; - setupDeviceOwner(); - // Lock task policy is updated when loading user data. - verifyLockTaskState(UserHandle.USER_SYSTEM); - - // Set up a managed profile managed by different package (package name shouldn't matter) - final int MANAGED_PROFILE_USER_ID = 15; - final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456); - final ComponentName adminDifferentPackage = - new ComponentName("another.package", "whatever.class"); - addManagedProfile(adminDifferentPackage, MANAGED_PROFILE_ADMIN_UID, admin2); - verifyLockTaskState(MANAGED_PROFILE_USER_ID); - - // Setup a PO on the secondary user - mContext.binder.callingUid = DpmMockContext.CALLER_UID; - setAsProfileOwner(admin3); - verifyLockTaskState(DpmMockContext.CALLER_USER_HANDLE); - - // The DO can still set lock task packages - final String[] doPackages = {"doPackage1", "doPackage2"}; - final int flags = DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS - | DevicePolicyManager.LOCK_TASK_FEATURE_HOME - | DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW; - verifyCanSetLockTask(DpmMockContext.CALLER_SYSTEM_USER_UID, UserHandle.USER_SYSTEM, admin1, doPackages, flags); - - final String[] secondaryPoPackages = {"secondaryPoPackage1", "secondaryPoPackage2"}; - final int secondaryPoFlags = DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS - | DevicePolicyManager.LOCK_TASK_FEATURE_HOME - | DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW; - verifyCanNotSetLockTask(DpmMockContext.CALLER_UID, admin3, secondaryPoPackages, secondaryPoFlags); - - // Managed profile is unaffiliated - shouldn't be able to setLockTaskPackages. - mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - final String[] poPackages = {"poPackage1", "poPackage2"}; - final int poFlags = DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS - | DevicePolicyManager.LOCK_TASK_FEATURE_HOME - | DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW; - verifyCanNotSetLockTask(MANAGED_PROFILE_ADMIN_UID, adminDifferentPackage, poPackages, poFlags); - - // Setting same affiliation ids - final Set<String> userAffiliationIds = Collections.singleton("some-affiliation-id"); - mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; - dpm.setAffiliationIds(admin1, userAffiliationIds); - - mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - dpm.setAffiliationIds(adminDifferentPackage, userAffiliationIds); - - // Now the managed profile can set lock task packages. - dpm.setLockTaskPackages(adminDifferentPackage, poPackages); - MoreAsserts.assertEquals(poPackages, dpm.getLockTaskPackages(adminDifferentPackage)); - assertTrue(dpm.isLockTaskPermitted("poPackage1")); - assertFalse(dpm.isLockTaskPermitted("doPackage2")); - // And it can set lock task features. - dpm.setLockTaskFeatures(adminDifferentPackage, poFlags); - verifyLockTaskState(MANAGED_PROFILE_USER_ID, poPackages, poFlags); - - // Unaffiliate the profile, lock task mode no longer available on the profile. - dpm.setAffiliationIds(adminDifferentPackage, Collections.emptySet()); - assertFalse(dpm.isLockTaskPermitted("poPackage1")); - // Lock task packages cleared when loading user data and when the user becomes unaffiliated. - verify(getServices().iactivityManager, times(2)).updateLockTaskPackages( - MANAGED_PROFILE_USER_ID, new String[0]); - verify(getServices().iactivityTaskManager, times(2)).updateLockTaskFeatures( - MANAGED_PROFILE_USER_ID, DevicePolicyManager.LOCK_TASK_FEATURE_NONE); - - // Verify that lock task packages were not cleared for the DO - mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; - assertTrue(dpm.isLockTaskPermitted("doPackage1")); - - } - public void testLockTaskPolicyForProfileOwner() throws Exception { // Setup a PO mContext.binder.callingUid = DpmMockContext.CALLER_UID; diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java index 1dd7e64690c7..6aca58f400b3 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java @@ -23,7 +23,8 @@ import static android.app.usage.UsageEvents.Event.SLICE_PINNED_PRIV; import static android.app.usage.UsageEvents.Event.SYSTEM_INTERACTION; import static android.app.usage.UsageEvents.Event.USER_INTERACTION; import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT; -import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED; +import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM; +import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_USER; import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED; import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT; import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE; @@ -501,12 +502,18 @@ public class AppStandbyControllerTests { // Can force to NEVER mInjector.mElapsedRealtime = HOUR_MS; mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, - REASON_MAIN_FORCED); + REASON_MAIN_FORCED_BY_USER); assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1)); - // Prediction can't override FORCED reason + // Prediction can't override FORCED reasons + mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, + REASON_MAIN_FORCED_BY_SYSTEM); + mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET, + REASON_MAIN_PREDICTED); + assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); + mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT, - REASON_MAIN_FORCED); + REASON_MAIN_FORCED_BY_USER); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET, REASON_MAIN_PREDICTED); assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController, PACKAGE_1)); @@ -631,7 +638,7 @@ public class AppStandbyControllerTests { mInjector.mElapsedRealtime = 1 * RARE_THRESHOLD + 100; // Make sure app is in NEVER bucket mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER, - REASON_MAIN_FORCED); + REASON_MAIN_FORCED_BY_USER); mController.checkIdleStates(USER_ID); assertBucket(STANDBY_BUCKET_NEVER); diff --git a/telecomm/TEST_MAPPING b/telecomm/TEST_MAPPING new file mode 100644 index 000000000000..d58566673eec --- /dev/null +++ b/telecomm/TEST_MAPPING @@ -0,0 +1,29 @@ +{ + "presubmit": [ + { + "name": "TeleServiceTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "TelecomUnitTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "TelephonyProviderTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + } + ] +} + diff --git a/telephony/TEST_MAPPING b/telephony/TEST_MAPPING new file mode 100644 index 000000000000..d58566673eec --- /dev/null +++ b/telephony/TEST_MAPPING @@ -0,0 +1,29 @@ +{ + "presubmit": [ + { + "name": "TeleServiceTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "TelecomUnitTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "TelephonyProviderTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + } + ] +} + diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java index 31434c1d2adf..5e2e554b7764 100644 --- a/telephony/java/android/telephony/PreciseDataConnectionState.java +++ b/telephony/java/android/telephony/PreciseDataConnectionState.java @@ -20,6 +20,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; +import android.compat.Compatibility; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledAfter; import android.compat.annotation.UnsupportedAppUsage; import android.net.LinkProperties; import android.os.Build; @@ -31,8 +34,6 @@ import android.telephony.Annotation.DataState; import android.telephony.Annotation.NetworkType; import android.telephony.data.ApnSetting; -import dalvik.system.VMRuntime; - import java.util.Objects; @@ -134,6 +135,13 @@ public final class PreciseDataConnectionState implements Parcelable { } /** + * To check the SDK version for {@link PreciseDataConnectionState#getDataConnectionState}. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R) + private static final long GET_DATA_CONNECTION_STATE_CODE_CHANGE = 147600208L; + + /** * Returns the state of data connection that supported the apn types returned by * {@link #getDataConnectionApnTypeBitMask()} * @@ -144,7 +152,7 @@ public final class PreciseDataConnectionState implements Parcelable { @SystemApi public @DataState int getDataConnectionState() { if (mState == TelephonyManager.DATA_DISCONNECTING - && VMRuntime.getRuntime().getTargetSdkVersion() < Build.VERSION_CODES.R) { + && !Compatibility.isChangeEnabled(GET_DATA_CONNECTION_STATE_CODE_CHANGE)) { return TelephonyManager.DATA_CONNECTED; } diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index da0ac39fe1d3..8ed4ee594d73 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -281,6 +281,42 @@ public final class SmsManager { */ public static final int SMS_MESSAGE_PERIOD_NOT_SPECIFIED = -1; + /** @hide */ + @IntDef(prefix = { "PREMIUM_SMS_CONSENT" }, value = { + SmsManager.PREMIUM_SMS_CONSENT_UNKNOWN, + SmsManager.PREMIUM_SMS_CONSENT_ASK_USER, + SmsManager.PREMIUM_SMS_CONSENT_NEVER_ALLOW, + SmsManager.PREMIUM_SMS_CONSENT_ALWAYS_ALLOW + }) + @Retention(RetentionPolicy.SOURCE) + public @interface PremiumSmsConsent {} + + /** Premium SMS Consent for the package is unknown. This indicates that the user + * has not set a permission for this package, because this package has never tried + * to send a premium SMS. + * @hide + */ + @SystemApi + public static final int PREMIUM_SMS_CONSENT_UNKNOWN = 0; + + /** Default premium SMS Consent (ask user for each premium SMS sent). + * @hide + */ + @SystemApi + public static final int PREMIUM_SMS_CONSENT_ASK_USER = 1; + + /** Premium SMS Consent when the owner has denied the app from sending premium SMS. + * @hide + */ + @SystemApi + public static final int PREMIUM_SMS_CONSENT_NEVER_ALLOW = 2; + + /** Premium SMS Consent when the owner has allowed the app to send premium SMS. + * @hide + */ + @SystemApi + public static final int PREMIUM_SMS_CONSENT_ALWAYS_ALLOW = 3; + // result of asking the user for a subscription to perform an operation. private interface SubscriptionResolverResult { void onSuccess(int subId); @@ -744,7 +780,11 @@ public final class SmsManager { "Invalid pdu format. format must be either 3gpp or 3gpp2"); } try { - ISms iSms = TelephonyManager.getSmsService(); + ISms iSms = ISms.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSmsServiceRegisterer() + .get()); if (iSms != null) { iSms.injectSmsPduForSubscriber( getSubscriptionId(), pdu, format, receivedIntent); @@ -1567,7 +1607,7 @@ public final class SmsManager { * the service does not exist. */ private static ISms getISmsServiceOrThrow() { - ISms iSms = TelephonyManager.getSmsService(); + ISms iSms = getISmsService(); if (iSms == null) { throw new UnsupportedOperationException("Sms is not supported"); } @@ -1575,7 +1615,11 @@ public final class SmsManager { } private static ISms getISmsService() { - return TelephonyManager.getSmsService(); + return ISms.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSmsServiceRegisterer() + .get()); } /** @@ -2009,7 +2053,11 @@ public final class SmsManager { public boolean isSMSPromptEnabled() { ISms iSms = null; try { - iSms = TelephonyManager.getSmsService(); + iSms = ISms.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSmsServiceRegisterer() + .get()); return iSms.isSMSPromptEnabled(); } catch (RemoteException ex) { return false; @@ -2857,4 +2905,53 @@ public final class SmsManager { } return false; } + + /** + * Gets the premium SMS permission for the specified package. If the package has never + * been seen before, the default {@link SmsManager#PREMIUM_SMS_PERMISSION_ASK_USER} + * will be returned. + * @param packageName the name of the package to query permission + * @return one of {@link SmsManager#PREMIUM_SMS_CONSENT_UNKNOWN}, + * {@link SmsManager#PREMIUM_SMS_CONSENT_ASK_USER}, + * {@link SmsManager#PREMIUM_SMS_CONSENT_NEVER_ALLOW}, or + * {@link SmsManager#PREMIUM_SMS_CONSENT_ALWAYS_ALLOW} + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public @PremiumSmsConsent int getPremiumSmsConsent(@NonNull String packageName) { + int permission = 0; + try { + ISms iSms = getISmsService(); + if (iSms != null) { + permission = iSms.getPremiumSmsPermission(packageName); + } + } catch (RemoteException e) { + Log.e(TAG, "getPremiumSmsPermission() RemoteException", e); + } + return permission; + } + + /** + * Sets the premium SMS permission for the specified package and save the value asynchronously + * to persistent storage. + * @param packageName the name of the package to set permission + * @param permission one of {@link SmsManager#PREMIUM_SMS_CONSENT_ASK_USER}, + * {@link SmsManager#PREMIUM_SMS_CONSENT_NEVER_ALLOW}, or + * {@link SmsManager#PREMIUM_SMS_CONSENT_ALWAYS_ALLOW} + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void setPremiumSmsConsent( + @NonNull String packageName, @PremiumSmsConsent int permission) { + try { + ISms iSms = getISmsService(); + if (iSms != null) { + iSms.setPremiumSmsPermission(packageName, permission); + } + } catch (RemoteException e) { + Log.e(TAG, "setPremiumSmsPermission() RemoteException", e); + } + } } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index cb4462f88581..36f541f0a81d 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -16,8 +16,6 @@ package android.telephony; -import com.android.telephony.Rlog; - import static android.net.NetworkPolicyManager.OVERRIDE_CONGESTED; import static android.net.NetworkPolicyManager.OVERRIDE_UNMETERED; @@ -67,6 +65,7 @@ import com.android.internal.telephony.ISub; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.util.HandlerExecutor; import com.android.internal.util.Preconditions; +import com.android.telephony.Rlog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -1146,7 +1145,11 @@ public class SubscriptionManager { SubscriptionInfo subInfo = null; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { subInfo = iSub.getActiveSubscriptionInfo(subId, mContext.getOpPackageName(), mContext.getFeatureId()); @@ -1180,7 +1183,11 @@ public class SubscriptionManager { SubscriptionInfo result = null; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { result = iSub.getActiveSubscriptionInfoForIccId(iccId, mContext.getOpPackageName(), mContext.getFeatureId()); @@ -1214,7 +1221,11 @@ public class SubscriptionManager { SubscriptionInfo result = null; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIndex, mContext.getOpPackageName(), mContext.getFeatureId()); @@ -1238,7 +1249,11 @@ public class SubscriptionManager { List<SubscriptionInfo> result = null; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { result = iSub.getAllSubInfoList(mContext.getOpPackageName(), mContext.getFeatureId()); @@ -1319,7 +1334,11 @@ public class SubscriptionManager { List<SubscriptionInfo> activeList = null; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { activeList = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName(), mContext.getFeatureId()); @@ -1370,7 +1389,11 @@ public class SubscriptionManager { List<SubscriptionInfo> result = null; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { result = iSub.getAvailableSubscriptionInfoList(mContext.getOpPackageName(), mContext.getFeatureId()); @@ -1409,7 +1432,11 @@ public class SubscriptionManager { List<SubscriptionInfo> result = null; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { result = iSub.getAccessibleSubscriptionInfoList(mContext.getOpPackageName()); } @@ -1438,7 +1465,11 @@ public class SubscriptionManager { public void requestEmbeddedSubscriptionInfoListRefresh() { int cardId = TelephonyManager.from(mContext).getCardIdForDefaultEuicc(); try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { iSub.requestEmbeddedSubscriptionInfoListRefresh(cardId); } @@ -1467,7 +1498,11 @@ public class SubscriptionManager { @SystemApi public void requestEmbeddedSubscriptionInfoListRefresh(int cardId) { try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { iSub.requestEmbeddedSubscriptionInfoListRefresh(cardId); } @@ -1488,7 +1523,11 @@ public class SubscriptionManager { int result = 0; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { result = iSub.getAllSubInfoCount(mContext.getOpPackageName(), mContext.getFeatureId()); @@ -1517,7 +1556,11 @@ public class SubscriptionManager { int result = 0; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { result = iSub.getActiveSubInfoCount(mContext.getOpPackageName(), mContext.getFeatureId()); @@ -1538,7 +1581,11 @@ public class SubscriptionManager { int result = 0; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { result = iSub.getActiveSubInfoCountMax(); } @@ -1595,7 +1642,11 @@ public class SubscriptionManager { } try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub == null) { Log.e(LOG_TAG, "[addSubscriptionInfoRecord]- ISub service is null"); return; @@ -1629,7 +1680,11 @@ public class SubscriptionManager { } try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub == null) { Log.e(LOG_TAG, "[removeSubscriptionInfoRecord]- ISub service is null"); return; @@ -1732,7 +1787,11 @@ public class SubscriptionManager { int result = INVALID_SIM_SLOT_INDEX; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { result = iSub.getSlotIndex(subscriptionId); } @@ -1766,7 +1825,11 @@ public class SubscriptionManager { int[] subId = null; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { subId = iSub.getSubId(slotIndex); } @@ -1790,7 +1853,11 @@ public class SubscriptionManager { int result = INVALID_PHONE_INDEX; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { result = iSub.getPhoneId(subId); } @@ -1824,7 +1891,11 @@ public class SubscriptionManager { int subId = INVALID_SUBSCRIPTION_ID; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { subId = iSub.getDefaultSubId(); } @@ -1847,7 +1918,11 @@ public class SubscriptionManager { int subId = INVALID_SUBSCRIPTION_ID; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { subId = iSub.getDefaultVoiceSubId(); } @@ -1877,7 +1952,11 @@ public class SubscriptionManager { public void setDefaultVoiceSubscriptionId(int subscriptionId) { if (VDBG) logd("setDefaultVoiceSubId sub id = " + subscriptionId); try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { iSub.setDefaultVoiceSubId(subscriptionId); } @@ -1925,7 +2004,11 @@ public class SubscriptionManager { int subId = INVALID_SUBSCRIPTION_ID; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { subId = iSub.getDefaultSmsSubId(); } @@ -1951,7 +2034,11 @@ public class SubscriptionManager { public void setDefaultSmsSubId(int subscriptionId) { if (VDBG) logd("setDefaultSmsSubId sub id = " + subscriptionId); try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { iSub.setDefaultSmsSubId(subscriptionId); } @@ -1989,7 +2076,11 @@ public class SubscriptionManager { int subId = INVALID_SUBSCRIPTION_ID; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { subId = iSub.getDefaultDataSubId(); } @@ -2015,7 +2106,11 @@ public class SubscriptionManager { public void setDefaultDataSubId(int subscriptionId) { if (VDBG) logd("setDataSubscription sub id = " + subscriptionId); try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { iSub.setDefaultDataSubId(subscriptionId); } @@ -2046,7 +2141,11 @@ public class SubscriptionManager { /** @hide */ public void clearSubscriptionInfo() { try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { iSub.clearSubInfo(); } @@ -2140,10 +2239,9 @@ public class SubscriptionManager { @UnsupportedAppUsage public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId, int subId) { if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId); - intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); - intent.putExtra(EXTRA_SUBSCRIPTION_INDEX, subId); intent.putExtra(EXTRA_SLOT_INDEX, phoneId); intent.putExtra(PhoneConstants.PHONE_KEY, phoneId); + putSubscriptionIdExtra(intent, subId); } /** @@ -2182,7 +2280,11 @@ public class SubscriptionManager { */ public @NonNull int[] getActiveSubscriptionIdList(boolean visibleOnly) { try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { int[] subId = iSub.getActiveSubIdList(visibleOnly); if (subId != null) return subId; @@ -2233,7 +2335,11 @@ public class SubscriptionManager { int simState = TelephonyManager.SIM_STATE_UNKNOWN; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { simState = iSub.getSimStateForSlotIndex(slotIndex); } @@ -2252,7 +2358,11 @@ public class SubscriptionManager { */ public static void setSubscriptionProperty(int subId, String propKey, String propValue) { try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { iSub.setSubscriptionProperty(subId, propKey, propValue); } @@ -2272,7 +2382,11 @@ public class SubscriptionManager { Context context) { String resultValue = null; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { resultValue = iSub.getSubscriptionProperty(subId, propKey, context.getOpPackageName(), context.getFeatureId()); @@ -2414,7 +2528,11 @@ public class SubscriptionManager { @UnsupportedAppUsage public boolean isActiveSubId(int subId) { try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { return iSub.isActiveSubId(subId, mContext.getOpPackageName(), mContext.getFeatureId()); @@ -2717,7 +2835,11 @@ public class SubscriptionManager { @TelephonyManager.SetOpportunisticSubscriptionResult Consumer<Integer> callback) { if (VDBG) logd("[setPreferredDataSubscriptionId]+ subId:" + subId); try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub == null) return; ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() { @@ -2760,7 +2882,11 @@ public class SubscriptionManager { public int getPreferredDataSubscriptionId() { int preferredSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { preferredSubId = iSub.getPreferredDataSubscriptionId(); } @@ -2791,7 +2917,11 @@ public class SubscriptionManager { List<SubscriptionInfo> subInfoList = null; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { subInfoList = iSub.getOpportunisticSubscriptions(contextPkg, contextFeature); } @@ -2892,7 +3022,11 @@ public class SubscriptionManager { ParcelUuid groupUuid = null; int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray(); try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { groupUuid = iSub.createSubscriptionGroup(subIdArray, pkgForDebug); } else { @@ -2942,7 +3076,11 @@ public class SubscriptionManager { int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray(); try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { iSub.addSubscriptionsIntoGroup(subIdArray, groupUuid, pkgForDebug); } else { @@ -2994,7 +3132,11 @@ public class SubscriptionManager { int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray(); try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { iSub.removeSubscriptionsFromGroup(subIdArray, groupUuid, pkgForDebug); } else { @@ -3039,7 +3181,11 @@ public class SubscriptionManager { List<SubscriptionInfo> result = null; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { result = iSub.getSubscriptionsInGroup(groupUuid, contextPkg, contextFeature); } else { @@ -3152,7 +3298,11 @@ public class SubscriptionManager { logd("setSubscriptionActivated subId= " + subscriptionId + " enable " + enable); } try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { return iSub.setSubscriptionEnabled(enable, subscriptionId); } @@ -3241,7 +3391,11 @@ public class SubscriptionManager { @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSubscriptionEnabled(int subscriptionId) { try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { return iSub.isSubscriptionEnabled(subscriptionId); } @@ -3264,7 +3418,11 @@ public class SubscriptionManager { int subId = INVALID_SUBSCRIPTION_ID; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { subId = iSub.getEnabledSubscriptionId(slotIndex); } @@ -3290,7 +3448,11 @@ public class SubscriptionManager { int result = 0; try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { result = helper.callMethod(iSub); } @@ -3313,7 +3475,11 @@ public class SubscriptionManager { */ public static int getActiveDataSubscriptionId() { try { - ISub iSub = TelephonyManager.getSubscriptionService(); + ISub iSub = ISub.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer() + .get()); if (iSub != null) { return iSub.getActiveDataSubscriptionId(); } @@ -3321,4 +3487,19 @@ public class SubscriptionManager { } return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } + + /** + * Helper method that puts a subscription id on an intent with the constants: + * PhoneConstant.SUBSCRIPTION_KEY and SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX. + * Both constants are used to support backwards compatibility. Once we know we got all places, + * we can remove PhoneConstants.SUBSCRIPTION_KEY. + * @param intent Intent to put sub id on. + * @param subId SubscriptionId to put on intent. + * + * @hide + */ + public static void putSubscriptionIdExtra(Intent intent, int subId) { + intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); + intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); + } } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 00d9f3ca1728..0ffeccfa6a23 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -57,7 +57,6 @@ import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.os.IBinder; import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; @@ -95,15 +94,12 @@ import android.util.Log; import android.util.Pair; import com.android.ims.internal.IImsServiceFeatureCallback; -import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CellNetworkScanResult; import com.android.internal.telephony.INumberVerificationCallback; import com.android.internal.telephony.IOns; import com.android.internal.telephony.IPhoneSubInfo; import com.android.internal.telephony.ISetOpportunisticDataCallback; -import com.android.internal.telephony.ISms; -import com.android.internal.telephony.ISub; import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.ITelephonyRegistry; import com.android.internal.telephony.IUpdateAvailableNetworksCallback; @@ -113,8 +109,6 @@ import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.SmsApplication; import com.android.telephony.Rlog; -import dalvik.system.VMRuntime; - import java.io.FileInputStream; import java.io.IOException; import java.lang.annotation.Retention; @@ -305,21 +299,6 @@ public class TelephonyManager { private SubscriptionManager mSubscriptionManager; private TelephonyScanManager mTelephonyScanManager; - /** Cached service handles, cleared by resetServiceHandles() at death */ - private static final Object sCacheLock = new Object(); - - /** @hide */ - private static boolean sServiceHandleCacheEnabled = true; - - @GuardedBy("sCacheLock") - private static IPhoneSubInfo sIPhoneSubInfo; - @GuardedBy("sCacheLock") - private static ISub sISub; - @GuardedBy("sCacheLock") - private static ISms sISms; - @GuardedBy("sCacheLock") - private static final DeathRecipient sServiceDeath = new DeathRecipient(); - /** Enum indicating multisim variants * DSDS - Dual SIM Dual Standby * DSDA - Dual SIM Dual Active @@ -1465,7 +1444,8 @@ public class TelephonyManager { /** * <p>Broadcast Action: The emergency callback mode is changed. * <ul> - * <li><em>phoneinECMState</em> - A boolean value,true=phone in ECM, false=ECM off</li> + * <li><em>EXTRA_PHONE_IN_ECM_STATE</em> - A boolean value,true=phone in ECM, + * false=ECM off</li> * </ul> * <p class="note"> * You can <em>not</em> receive this through components declared @@ -1475,12 +1455,25 @@ public class TelephonyManager { * * <p class="note">This is a protected intent that can only be sent by the system. * + * @see #EXTRA_PHONE_IN_ECM_STATE + * * @hide */ @SystemApi @SuppressLint("ActionValue") - public static final String ACTION_EMERGENCY_CALLBACK_MODE_CHANGED - = "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED"; + public static final String ACTION_EMERGENCY_CALLBACK_MODE_CHANGED = + "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED"; + + + /** + * Extra included in {@link #ACTION_EMERGENCY_CALLBACK_MODE_CHANGED}. + * Indicates whether the phone is in an emergency phone state. + * + * @hide + */ + @SystemApi + public static final String EXTRA_PHONE_IN_ECM_STATE = + "android.telephony.extra.PHONE_IN_ECM_STATE"; /** * <p>Broadcast Action: when data connections get redirected with validation failure. @@ -1672,8 +1665,8 @@ public class TelephonyManager { /** * <p>Broadcast Action: The emergency call state is changed. * <ul> - * <li><em>phoneInEmergencyCall</em> - A boolean value, true if phone in emergency call, - * false otherwise</li> + * <li><em>EXTRA_PHONE_IN_EMERGENCY_CALL</em> - A boolean value, true if phone in emergency + * call, false otherwise</li> * </ul> * <p class="note"> * You can <em>not</em> receive this through components declared @@ -1683,12 +1676,25 @@ public class TelephonyManager { * * <p class="note">This is a protected intent that can only be sent by the system. * + * @see #EXTRA_PHONE_IN_EMERGENCY_CALL + * * @hide */ @SystemApi @SuppressLint("ActionValue") - public static final String ACTION_EMERGENCY_CALL_STATE_CHANGED - = "android.intent.action.EMERGENCY_CALL_STATE_CHANGED"; + public static final String ACTION_EMERGENCY_CALL_STATE_CHANGED = + "android.intent.action.EMERGENCY_CALL_STATE_CHANGED"; + + + /** + * Extra included in {@link #ACTION_EMERGENCY_CALL_STATE_CHANGED}. + * It indicates whether the phone is making an emergency call. + * + * @hide + */ + @SystemApi + public static final String EXTRA_PHONE_IN_EMERGENCY_CALL = + "android.telephony.extra.PHONE_IN_EMERGENCY_CALL"; /** * <p>Broadcast Action: It indicates the Emergency callback mode blocks datacall/sms @@ -1701,8 +1707,8 @@ public class TelephonyManager { * @hide */ @SystemApi - public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS - = "android.telephony.action.SHOW_NOTICE_ECM_BLOCK_OTHERS"; + public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS = + "android.telephony.action.SHOW_NOTICE_ECM_BLOCK_OTHERS"; /** * Broadcast Action: The default data subscription has changed in a multi-SIM device. @@ -1715,8 +1721,8 @@ public class TelephonyManager { */ @SystemApi @SuppressLint("ActionValue") - public static final String ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED - = "android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED"; + public static final String ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED = + "android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED"; /** * Broadcast Action: The default voice subscription has changed in a mult-SIm device. @@ -1729,8 +1735,8 @@ public class TelephonyManager { */ @SystemApi @SuppressLint("ActionValue") - public static final String ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED - = "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED"; + public static final String ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED = + "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED"; /** * Broadcast Action: This triggers a client initiated OMA-DM session to the OMA server. @@ -1743,8 +1749,8 @@ public class TelephonyManager { */ @SystemApi @SuppressLint("ActionValue") - public static final String ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE - = "com.android.omadm.service.CONFIGURATION_UPDATE"; + public static final String ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE = + "com.android.omadm.service.CONFIGURATION_UPDATE"; // // @@ -1868,7 +1874,7 @@ public class TelephonyManager { public String getDeviceId(int slotIndex) { // FIXME this assumes phoneId == slotIndex try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getDeviceIdForPhone(slotIndex, mContext.getOpPackageName(), @@ -2122,7 +2128,7 @@ public class TelephonyManager { private String getNaiBySubscriberId(int subId) { try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; String nai = info.getNaiForSubscriber(subId, mContext.getOpPackageName(), @@ -3811,7 +3817,7 @@ public class TelephonyManager { @UnsupportedAppUsage public String getSimSerialNumber(int subId) { try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getIccSerialNumberForSubscriber(subId, mContext.getOpPackageName(), @@ -4085,7 +4091,7 @@ public class TelephonyManager { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public String getSubscriberId(int subId) { try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getSubscriberIdForSubscriber(subId, mContext.getOpPackageName(), @@ -4121,7 +4127,7 @@ public class TelephonyManager { @Nullable public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(@KeyType int keyType) { try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) { Rlog.e(TAG,"IMSI error: Subscriber Info is null"); return null; @@ -4164,7 +4170,7 @@ public class TelephonyManager { @SystemApi public void resetCarrierKeysForImsiEncryption() { try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) { Rlog.e(TAG, "IMSI error: Subscriber Info is null"); if (!isSystemProcess()) { @@ -4229,7 +4235,7 @@ public class TelephonyManager { */ public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo) { try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return; info.setCarrierInfoForImsiEncryption(mSubId, mContext.getOpPackageName(), imsiEncryptionInfo); @@ -4253,7 +4259,7 @@ public class TelephonyManager { @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getGroupIdLevel1() { try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getGroupIdLevel1ForSubscriber(getSubId(), mContext.getOpPackageName(), @@ -4277,7 +4283,7 @@ public class TelephonyManager { @UnsupportedAppUsage public String getGroupIdLevel1(int subId) { try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getGroupIdLevel1ForSubscriber(subId, mContext.getOpPackageName(), @@ -4340,7 +4346,7 @@ public class TelephonyManager { return number; } try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getLine1NumberForSubscriber(subId, mContext.getOpPackageName(), @@ -4431,7 +4437,7 @@ public class TelephonyManager { return alphaTag; } try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getLine1AlphaTagForSubscriber(subId, getOpPackageName(), @@ -4519,7 +4525,7 @@ public class TelephonyManager { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public String getMsisdn(int subId) { try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getMsisdnForSubscriber(subId, getOpPackageName(), getFeatureId()); @@ -4553,7 +4559,7 @@ public class TelephonyManager { @UnsupportedAppUsage public String getVoiceMailNumber(int subId) { try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getVoiceMailNumberForSubscriber(subId, getOpPackageName(), @@ -5152,7 +5158,7 @@ public class TelephonyManager { @UnsupportedAppUsage public String getVoiceMailAlphaTag(int subId) { try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getVoiceMailAlphaTagForSubscriber(subId, getOpPackageName(), @@ -5200,7 +5206,7 @@ public class TelephonyManager { @UnsupportedAppUsage public String getIsimImpi() { try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; //get the Isim Impi based on subId @@ -5227,7 +5233,7 @@ public class TelephonyManager { @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain() { try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; //get the Isim Domain based on subId @@ -5251,7 +5257,7 @@ public class TelephonyManager { @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String[] getIsimImpu() { try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; //get the Isim Impu based on subId @@ -5264,6 +5270,19 @@ public class TelephonyManager { } } + /** + * @hide + */ + @UnsupportedAppUsage + private IPhoneSubInfo getSubscriberInfo() { + // get it each time because that process crashes a lot + return IPhoneSubInfo.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getPhoneSubServiceRegisterer() + .get()); + } + /** * Device call state: No activity. */ @@ -5417,6 +5436,13 @@ public class TelephonyManager { public static final int DATA_DISCONNECTING = 4; /** + * To check the SDK version for {@link TelephonyManager#getDataState}. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R) + private static final long GET_DATA_STATE_CODE_CHANGE = 147600208L; + + /** * Returns a constant indicating the current data connection state * (cellular). * @@ -5434,7 +5460,7 @@ public class TelephonyManager { int state = telephony.getDataStateForSubId( getSubId(SubscriptionManager.getActiveDataSubscriptionId())); if (state == TelephonyManager.DATA_DISCONNECTING - && VMRuntime.getRuntime().getTargetSdkVersion() < Build.VERSION_CODES.R) { + && !Compatibility.isChangeEnabled(GET_DATA_STATE_CODE_CHANGE)) { return TelephonyManager.DATA_CONNECTED; } @@ -5496,6 +5522,13 @@ public class TelephonyManager { // /** + * To check the SDK version for {@link TelephonyManager#listen}. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) + private static final long LISTEN_CODE_CHANGE = 147600208L; + + /** * Registers a listener object to receive notification of changes * in specified telephony states. * <p> @@ -5534,7 +5567,7 @@ public class TelephonyManager { // subId from PhoneStateListener is deprecated Q on forward, use the subId from // TelephonyManager instance. keep using subId from PhoneStateListener for pre-Q. int subId = mSubId; - if (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q) { + if (Compatibility.isChangeEnabled(LISTEN_CODE_CHANGE)) { // since mSubId in PhoneStateListener is deprecated from Q on forward, this is // the only place to set mSubId and its for "informational" only. // TODO: remove this once we completely get rid of mSubId in PhoneStateListener @@ -7000,7 +7033,7 @@ public class TelephonyManager { @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst() { try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; //get the Isim Ist based on subId @@ -7022,7 +7055,7 @@ public class TelephonyManager { @UnsupportedAppUsage public String[] getIsimPcscf() { try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; //get the Isim Pcscf based on subId @@ -7103,7 +7136,7 @@ public class TelephonyManager { @UnsupportedAppUsage public String getIccAuthentication(int subId, int appType, int authType, String data) { try { - IPhoneSubInfo info = getSubscriberInfoService(); + IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getIccSimChallengeResponse(subId, appType, authType, data); @@ -12379,150 +12412,4 @@ public class TelephonyManager { } return false; } - - private static class DeathRecipient implements IBinder.DeathRecipient { - @Override - public void binderDied() { - resetServiceCache(); - } - } - - /** - * Reset everything in the service cache; if one handle died then they are - * all probably broken. - * @hide - */ - private static void resetServiceCache() { - synchronized (sCacheLock) { - if (sISub != null) { - sISub.asBinder().unlinkToDeath(sServiceDeath, 0); - sISub = null; - } - if (sISms != null) { - sISms.asBinder().unlinkToDeath(sServiceDeath, 0); - sISms = null; - } - if (sIPhoneSubInfo != null) { - sIPhoneSubInfo.asBinder().unlinkToDeath(sServiceDeath, 0); - sIPhoneSubInfo = null; - } - } - } - - /** - * @hide - */ - static IPhoneSubInfo getSubscriberInfoService() { - if (!sServiceHandleCacheEnabled) { - return IPhoneSubInfo.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getPhoneSubServiceRegisterer() - .get()); - } - - if (sIPhoneSubInfo == null) { - IPhoneSubInfo temp = IPhoneSubInfo.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getPhoneSubServiceRegisterer() - .get()); - synchronized (sCacheLock) { - if (sIPhoneSubInfo == null && temp != null) { - try { - sIPhoneSubInfo = temp; - sIPhoneSubInfo.asBinder().linkToDeath(sServiceDeath, 0); - } catch (Exception e) { - // something has gone horribly wrong - sIPhoneSubInfo = null; - } - } - } - } - return sIPhoneSubInfo; - } - - /** - * @hide - */ - static ISub getSubscriptionService() { - if (!sServiceHandleCacheEnabled) { - return ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); - } - - if (sISub == null) { - ISub temp = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); - synchronized (sCacheLock) { - if (sISub == null && temp != null) { - try { - sISub = temp; - sISub.asBinder().linkToDeath(sServiceDeath, 0); - } catch (Exception e) { - // something has gone horribly wrong - sISub = null; - } - } - } - } - return sISub; - } - - /** - * @hide - */ - static ISms getSmsService() { - if (!sServiceHandleCacheEnabled) { - return ISms.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSmsServiceRegisterer() - .get()); - } - - if (sISms == null) { - ISms temp = ISms.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSmsServiceRegisterer() - .get()); - synchronized (sCacheLock) { - if (sISms == null && temp != null) { - try { - sISms = temp; - sISms.asBinder().linkToDeath(sServiceDeath, 0); - } catch (Exception e) { - // something has gone horribly wrong - sISms = null; - } - } - } - } - return sISms; - } - - /** - * Disables service handle caching for tests that utilize mock services. - * @hide - */ - @VisibleForTesting - public static void disableServiceHandleCaching() { - sServiceHandleCacheEnabled = false; - } - - /** - * Reenables service handle caching. - * @hide - */ - @VisibleForTesting - public static void enableServiceHandleCaching() { - sServiceHandleCacheEnabled = true; - } } diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java index 51701eb4ace5..db8c84560282 100644 --- a/telephony/java/com/android/internal/telephony/PhoneConstants.java +++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java @@ -100,9 +100,6 @@ public class PhoneConstants { public static final String DATA_APN_TYPE_KEY = "apnType"; public static final String DATA_APN_KEY = "apn"; - public static final String PHONE_IN_ECM_STATE = "phoneinECMState"; - public static final String PHONE_IN_EMERGENCY_CALL = "phoneInEmergencyCall"; - /** * Return codes for supplyPinReturnResult and * supplyPukReturnResult APIs diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java index 0ab5c97d317e..11d5b250d752 100644 --- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java +++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java @@ -222,7 +222,7 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { @Override public Network getNetwork() { - return new Network(mNetworkAgent.netId); + return mNetworkAgent.network; } public void expectPreventReconnectReceived(long timeoutMs) { diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index b2d363e27839..1901a1db633b 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -575,7 +575,7 @@ public class ConnectivityServiceTest { } }; - assertEquals(na.netId, nmNetworkCaptor.getValue().netId); + assertEquals(na.network.netId, nmNetworkCaptor.getValue().netId); mNmCallbacks = nmCbCaptor.getValue(); mNmCallbacks.onNetworkMonitorCreated(mNetworkMonitor); diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java index 9e915aec6832..e863266c4b49 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java @@ -35,7 +35,6 @@ import android.net.ConnectivityManager; import android.net.IDnsResolver; import android.net.INetd; import android.net.Network; -import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkProvider; @@ -75,7 +74,6 @@ public class LingerMonitorTest { @Mock INetd mNetd; @Mock INetworkManagementService mNMS; @Mock Context mCtx; - @Mock NetworkAgentConfig mAgentConfig; @Mock NetworkNotificationManager mNotifier; @Mock Resources mResources; @@ -358,7 +356,7 @@ public class LingerMonitorTest { NetworkScore ns = new NetworkScore(); ns.putIntExtension(NetworkScore.LEGACY_SCORE, 50); NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null, - caps, ns, mCtx, null, mAgentConfig, mConnService, mNetd, mDnsResolver, mNMS, + caps, ns, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS, NetworkProvider.ID_NONE); 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 cf70f5d499d1..9b248878fe96 100644 --- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java +++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java @@ -63,7 +63,6 @@ public class Nat464XlatTest { static final int NETID = 42; @Mock ConnectivityService mConnectivity; - @Mock NetworkAgentConfig mAgentConfig; @Mock IDnsResolver mDnsResolver; @Mock INetd mNetd; @Mock INetworkManagementService mNms; @@ -72,6 +71,7 @@ public class Nat464XlatTest { TestLooper mLooper; Handler mHandler; + NetworkAgentConfig mAgentConfig = new NetworkAgentConfig(); Nat464Xlat makeNat464Xlat() { return new Nat464Xlat(mNai, mNetd, mDnsResolver, mNms) { diff --git a/wifi/Android.bp b/wifi/Android.bp index 6326f14bc6fd..70c9befce66a 100644 --- a/wifi/Android.bp +++ b/wifi/Android.bp @@ -50,6 +50,8 @@ test_access_hidden_api_whitelist = [ "//frameworks/opt/net/wifi/libs/WifiTrackerLib/tests", "//external/robolectric-shadows:__subpackages__", + "//frameworks/base/packages/SettingsLib/tests/integ", + "//external/sl4a:__subpackages__", ] // wifi-service needs pre-jarjared version of framework-wifi so it can reference copied utility diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java index c6aca07ebe94..341330587614 100644 --- a/wifi/java/android/net/wifi/ScanResult.java +++ b/wifi/java/android/net/wifi/ScanResult.java @@ -23,6 +23,8 @@ import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.annotations.VisibleForTesting; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -793,10 +795,19 @@ public class ScanResult implements Parcelable { } } - /** empty scan result + /** + * Construct an empty scan result. * - * {@hide} - * */ + * Test code has a need to construct a ScanResult in a specific state. + * (Note that mocking using Mockito does not work if the object needs to be parceled and + * unparceled.) + * Export a @SystemApi default constructor to allow tests to construct an empty ScanResult + * object. The test can then directly set the fields it cares about. + * + * @hide + */ + @SystemApi + @VisibleForTesting public ScanResult() { } diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index f4c5b9168cd0..ee2b57535b50 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -39,6 +39,8 @@ import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; +import com.android.internal.annotations.VisibleForTesting; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; @@ -1208,22 +1210,27 @@ public class WifiConfiguration implements Parcelable { */ @SystemApi public static class NetworkSelectionStatus { - // Quality Network Selection Status enable, temporary disabled, permanently disabled + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "NETWORK_SELECTION_", + value = { + NETWORK_SELECTION_ENABLED, + NETWORK_SELECTION_TEMPORARY_DISABLED, + NETWORK_SELECTION_PERMANENTLY_DISABLED}) + public @interface NetworkEnabledStatus {} /** - * This network is allowed to join Quality Network Selection - * @hide + * This network will be considered as a potential candidate to connect to during network + * selection. */ public static final int NETWORK_SELECTION_ENABLED = 0; /** - * network was temporary disabled. Can be re-enabled after a time period expire - * @hide + * This network was temporary disabled. May be re-enabled after a time out. */ - public static final int NETWORK_SELECTION_TEMPORARY_DISABLED = 1; + public static final int NETWORK_SELECTION_TEMPORARY_DISABLED = 1; /** - * network was permanently disabled. - * @hide + * This network was permanently disabled. */ - public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED = 2; + public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED = 2; /** * Maximum Network selection status * @hide @@ -1455,6 +1462,7 @@ public class WifiConfiguration implements Parcelable { * Network selection status, should be in one of three status: enable, temporaily disabled * or permanently disabled */ + @NetworkEnabledStatus private int mStatus; /** @@ -1635,6 +1643,56 @@ public class WifiConfiguration implements Parcelable { } /** + * NetworkSelectionStatus exports an immutable public API. + * However, test code has a need to construct a NetworkSelectionStatus in a specific state. + * (Note that mocking using Mockito does not work if the object needs to be parceled and + * unparceled.) + * Export a @SystemApi Builder to allow tests to construct a NetworkSelectionStatus object + * in the desired state, without sacrificing NetworkSelectionStatus's immutability. + */ + @VisibleForTesting + public static final class Builder { + private final NetworkSelectionStatus mNetworkSelectionStatus = + new NetworkSelectionStatus(); + + /** + * Set the current network selection status. + * One of: + * {@link #NETWORK_SELECTION_ENABLED}, + * {@link #NETWORK_SELECTION_TEMPORARY_DISABLED}, + * {@link #NETWORK_SELECTION_PERMANENTLY_DISABLED} + * @see NetworkSelectionStatus#getNetworkSelectionStatus() + */ + @NonNull + public Builder setNetworkSelectionStatus(@NetworkEnabledStatus int status) { + mNetworkSelectionStatus.setNetworkSelectionStatus(status); + return this; + } + + /** + * + * Set the current network's disable reason. + * One of the {@link #NETWORK_SELECTION_ENABLE} or DISABLED_* constants. + * e.g. {@link #DISABLED_ASSOCIATION_REJECTION}. + * @see NetworkSelectionStatus#getNetworkSelectionDisableReason() + */ + @NonNull + public Builder setNetworkSelectionDisableReason( + @NetworkSelectionDisableReason int reason) { + mNetworkSelectionStatus.setNetworkSelectionDisableReason(reason); + return this; + } + + /** + * Build a NetworkSelectionStatus object. + */ + @NonNull + public NetworkSelectionStatus build() { + return mNetworkSelectionStatus; + } + } + + /** * Get the network disable reason string for a reason code (for debugging). * @param reason specific error reason. One of the {@link #NETWORK_SELECTION_ENABLE} or * DISABLED_* constants e.g. {@link #DISABLED_ASSOCIATION_REJECTION}. @@ -1660,10 +1718,13 @@ public class WifiConfiguration implements Parcelable { } /** - * get current network network selection status - * @return return current network network selection status - * @hide + * Get the current network network selection status. + * One of: + * {@link #NETWORK_SELECTION_ENABLED}, + * {@link #NETWORK_SELECTION_TEMPORARY_DISABLED}, + * {@link #NETWORK_SELECTION_PERMANENTLY_DISABLED} */ + @NetworkEnabledStatus public int getNetworkSelectionStatus() { return mStatus; } @@ -1965,10 +2026,11 @@ public class WifiConfiguration implements Parcelable { } /** - * Set the network selection status + * Set the network selection status. * @hide */ - public void setNetworkSelectionStatus(NetworkSelectionStatus status) { + @SystemApi + public void setNetworkSelectionStatus(@NonNull NetworkSelectionStatus status) { mNetworkSelectionStatus = status; } diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java index 41f7c6e2bb0d..5edcc2df3804 100644 --- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java +++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java @@ -1028,8 +1028,10 @@ public class WifiEnterpriseConfig implements Parcelable { } /** - * @hide + * Get the client private key as supplied in {@link #setClientKeyEntryWithCertificateChain}, or + * null if unset. */ + @Nullable public PrivateKey getClientPrivateKey() { return mClientPrivateKey; } diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index 62337cbf7e22..51b15afec3ab 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -17,6 +17,7 @@ package android.net.wifi; import android.annotation.IntRange; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; @@ -27,6 +28,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; +import com.android.internal.annotations.VisibleForTesting; + import java.net.Inet4Address; import java.net.InetAddress; import java.net.UnknownHostException; @@ -356,6 +359,72 @@ public class WifiInfo implements Parcelable { } } + /** + * WifiInfo exports an immutable public API. + * However, test code has a need to construct a WifiInfo in a specific state. + * (Note that mocking using Mockito does not work if the object needs to be parceled and + * unparceled.) + * Export a @SystemApi Builder to allow tests to construct a WifiInfo object + * in the desired state, without sacrificing WifiInfo's immutability. + * + * @hide + */ + // This builder was not made public to reduce confusion for external developers as there are + // no legitimate uses for this builder except for testing. + @SystemApi + @VisibleForTesting + public static final class Builder { + private final WifiInfo mWifiInfo = new WifiInfo(); + + /** + * Set the SSID, in the form of a raw byte array. + * @see WifiInfo#getSSID() + */ + @NonNull + public Builder setSsid(@NonNull byte[] ssid) { + mWifiInfo.setSSID(WifiSsid.createFromByteArray(ssid)); + return this; + } + + /** + * Set the BSSID. + * @see WifiInfo#getBSSID() + */ + @NonNull + public Builder setBssid(@NonNull String bssid) { + mWifiInfo.setBSSID(bssid); + return this; + } + + /** + * Set the RSSI, in dBm. + * @see WifiInfo#getRssi() + */ + @NonNull + public Builder setRssi(int rssi) { + mWifiInfo.setRssi(rssi); + return this; + } + + /** + * Set the network ID. + * @see WifiInfo#getNetworkId() + */ + @NonNull + public Builder setNetworkId(int networkId) { + mWifiInfo.setNetworkId(networkId); + return this; + } + + /** + * Build a WifiInfo object. + */ + @NonNull + public WifiInfo build() { + return mWifiInfo; + } + } + /** @hide */ public void setSSID(WifiSsid wifiSsid) { mWifiSsid = wifiSsid; diff --git a/wifi/tests/Android.bp b/wifi/tests/Android.bp new file mode 100644 index 000000000000..6a39959e8cfd --- /dev/null +++ b/wifi/tests/Android.bp @@ -0,0 +1,50 @@ +// Copyright (C) 2020 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. + +// Make test APK +// ============================================================ + +android_test { + name: "FrameworksWifiApiTests", + + defaults: ["framework-wifi-test-defaults"], + + srcs: ["**/*.java"], + + jacoco: { + include_filter: ["android.net.wifi.*"], + // TODO(b/147521214) need to exclude test classes + exclude_filter: [], + }, + + static_libs: [ + "androidx.test.rules", + "core-test-rules", + "guava", + "mockito-target-minus-junit4", + "net-tests-utils", + "frameworks-base-testutils", + "truth-prebuilt", + ], + + libs: [ + "android.test.runner", + "android.test.base", + ], + + test_suites: [ + "device-tests", + "mts", + ], +} diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk deleted file mode 100644 index d2c385b46eb1..000000000000 --- a/wifi/tests/Android.mk +++ /dev/null @@ -1,66 +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. - -LOCAL_PATH:= $(call my-dir) - -# Make test APK -# ============================================================ -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := tests - -LOCAL_SRC_FILES := $(call all-subdir-java-files) - -# This list is generated from the java source files in this module -# The list is a comma separated list of class names with * matching zero or more characters. -# Example: -# Input files: src/com/android/server/wifi/Test.java src/com/android/server/wifi/AnotherTest.java -# Generated exclude list: com.android.server.wifi.Test*,com.android.server.wifi.AnotherTest* - -# Filter all src files to just java files -local_java_files := $(filter %.java,$(LOCAL_SRC_FILES)) -# Transform java file names into full class names. -# This only works if the class name matches the file name and the directory structure -# matches the package. -local_classes := $(subst /,.,$(patsubst src/%.java,%,$(local_java_files))) -# Convert class name list to jacoco exclude list -# This appends a * to all classes and replace the space separators with commas. -# These patterns will match all classes in this module and their inner classes. -jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes))) - -jacoco_include := android.net.wifi.* - -LOCAL_JACK_COVERAGE_INCLUDE_FILTER := $(jacoco_include) -LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude) - -LOCAL_STATIC_JAVA_LIBRARIES := \ - androidx.test.rules \ - core-test-rules \ - guava \ - mockito-target-minus-junit4 \ - net-tests-utils \ - frameworks-base-testutils \ - truth-prebuilt \ - -LOCAL_JAVA_LIBRARIES := \ - android.test.runner \ - android.test.base \ - -LOCAL_PACKAGE_NAME := FrameworksWifiApiTests -LOCAL_PRIVATE_PLATFORM_APIS := true -LOCAL_COMPATIBILITY_SUITE := \ - device-tests \ - mts \ - -include $(BUILD_PACKAGE) |