diff options
25 files changed, 451 insertions, 186 deletions
diff --git a/boot/hiddenapi/hiddenapi-max-target-o.txt b/boot/hiddenapi/hiddenapi-max-target-o.txt index e346ebf827ae..eddb1621a4fa 100644 --- a/boot/hiddenapi/hiddenapi-max-target-o.txt +++ b/boot/hiddenapi/hiddenapi-max-target-o.txt @@ -35278,14 +35278,6 @@ Landroid/net/DhcpResults;->setLeaseDuration(I)V Landroid/net/DhcpResults;->setServerAddress(Ljava/lang/String;)Z Landroid/net/DhcpResults;->setVendorInfo(Ljava/lang/String;)V Landroid/net/DhcpResults;->TAG:Ljava/lang/String; -Landroid/net/EthernetManager;-><init>(Landroid/content/Context;Landroid/net/IEthernetManager;)V -Landroid/net/EthernetManager;->mContext:Landroid/content/Context; -Landroid/net/EthernetManager;->mHandler:Landroid/os/Handler; -Landroid/net/EthernetManager;->mListeners:Ljava/util/ArrayList; -Landroid/net/EthernetManager;->mService:Landroid/net/IEthernetManager; -Landroid/net/EthernetManager;->mServiceListener:Landroid/net/IEthernetServiceListener$Stub; -Landroid/net/EthernetManager;->MSG_AVAILABILITY_CHANGED:I -Landroid/net/EthernetManager;->TAG:Ljava/lang/String; Landroid/net/EventLogTags;-><init>()V Landroid/net/EventLogTags;->NTP_FAILURE:I Landroid/net/EventLogTags;->NTP_SUCCESS:I @@ -35319,39 +35311,6 @@ Landroid/net/http/X509TrustManagerExtensions;->mCheckServerTrusted:Ljava/lang/re Landroid/net/http/X509TrustManagerExtensions;->mDelegate:Lcom/android/org/conscrypt/TrustManagerImpl; Landroid/net/http/X509TrustManagerExtensions;->mIsSameTrustConfiguration:Ljava/lang/reflect/Method; Landroid/net/http/X509TrustManagerExtensions;->mTrustManager:Ljavax/net/ssl/X509TrustManager; -Landroid/net/IEthernetManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V -Landroid/net/IEthernetManager$Stub$Proxy;->addListener(Landroid/net/IEthernetServiceListener;)V -Landroid/net/IEthernetManager$Stub$Proxy;->getAvailableInterfaces()[Ljava/lang/String; -Landroid/net/IEthernetManager$Stub$Proxy;->getConfiguration(Ljava/lang/String;)Landroid/net/IpConfiguration; -Landroid/net/IEthernetManager$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String; -Landroid/net/IEthernetManager$Stub$Proxy;->isAvailable(Ljava/lang/String;)Z -Landroid/net/IEthernetManager$Stub$Proxy;->mRemote:Landroid/os/IBinder; -Landroid/net/IEthernetManager$Stub$Proxy;->removeListener(Landroid/net/IEthernetServiceListener;)V -Landroid/net/IEthernetManager$Stub$Proxy;->setConfiguration(Ljava/lang/String;Landroid/net/IpConfiguration;)V -Landroid/net/IEthernetManager$Stub;-><init>()V -Landroid/net/IEthernetManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/IEthernetManager; -Landroid/net/IEthernetManager$Stub;->DESCRIPTOR:Ljava/lang/String; -Landroid/net/IEthernetManager$Stub;->TRANSACTION_addListener:I -Landroid/net/IEthernetManager$Stub;->TRANSACTION_getAvailableInterfaces:I -Landroid/net/IEthernetManager$Stub;->TRANSACTION_getConfiguration:I -Landroid/net/IEthernetManager$Stub;->TRANSACTION_isAvailable:I -Landroid/net/IEthernetManager$Stub;->TRANSACTION_removeListener:I -Landroid/net/IEthernetManager$Stub;->TRANSACTION_setConfiguration:I -Landroid/net/IEthernetManager;->addListener(Landroid/net/IEthernetServiceListener;)V -Landroid/net/IEthernetManager;->getAvailableInterfaces()[Ljava/lang/String; -Landroid/net/IEthernetManager;->getConfiguration(Ljava/lang/String;)Landroid/net/IpConfiguration; -Landroid/net/IEthernetManager;->isAvailable(Ljava/lang/String;)Z -Landroid/net/IEthernetManager;->removeListener(Landroid/net/IEthernetServiceListener;)V -Landroid/net/IEthernetManager;->setConfiguration(Ljava/lang/String;Landroid/net/IpConfiguration;)V -Landroid/net/IEthernetServiceListener$Stub$Proxy;-><init>(Landroid/os/IBinder;)V -Landroid/net/IEthernetServiceListener$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String; -Landroid/net/IEthernetServiceListener$Stub$Proxy;->mRemote:Landroid/os/IBinder; -Landroid/net/IEthernetServiceListener$Stub$Proxy;->onAvailabilityChanged(Ljava/lang/String;Z)V -Landroid/net/IEthernetServiceListener$Stub;-><init>()V -Landroid/net/IEthernetServiceListener$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/IEthernetServiceListener; -Landroid/net/IEthernetServiceListener$Stub;->DESCRIPTOR:Ljava/lang/String; -Landroid/net/IEthernetServiceListener$Stub;->TRANSACTION_onAvailabilityChanged:I -Landroid/net/IEthernetServiceListener;->onAvailabilityChanged(Ljava/lang/String;Z)V Landroid/net/IIpConnectivityMetrics$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/net/IIpConnectivityMetrics$Stub$Proxy;->addNetdEventCallback(ILandroid/net/INetdEventCallback;)Z Landroid/net/IIpConnectivityMetrics$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String; diff --git a/core/api/current.txt b/core/api/current.txt index 8337cb61455e..4f2a07bdaf34 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -25203,14 +25203,6 @@ package android.net { method public int getUid(); } - public final class EthernetNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { - ctor public EthernetNetworkSpecifier(@NonNull String); - method public int describeContents(); - method @Nullable public String getInterfaceName(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkSpecifier> CREATOR; - } - public final class Ikev2VpnProfile extends android.net.PlatformVpnProfile { method @NonNull public java.util.List<java.lang.String> getAllowedAlgorithms(); method public int getMaxMtu(); diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index a6278f87f485..9db3cdc1f03c 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -193,22 +193,6 @@ package android.media.session { package android.net { - public class EthernetManager { - method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void addInterfaceStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.EthernetManager.InterfaceStateListener); - method public void removeInterfaceStateListener(@NonNull android.net.EthernetManager.InterfaceStateListener); - method public void setIncludeTestInterfaces(boolean); - field public static final int ROLE_CLIENT = 1; // 0x1 - field public static final int ROLE_NONE = 0; // 0x0 - field public static final int ROLE_SERVER = 2; // 0x2 - field public static final int STATE_ABSENT = 0; // 0x0 - field public static final int STATE_LINK_DOWN = 1; // 0x1 - field public static final int STATE_LINK_UP = 2; // 0x2 - } - - public static interface EthernetManager.InterfaceStateListener { - method public void onInterfaceStateChanged(@NonNull String, int, int, @Nullable android.net.IpConfiguration); - } - public class LocalSocket implements java.io.Closeable { ctor public LocalSocket(@NonNull java.io.FileDescriptor); } @@ -219,7 +203,8 @@ package android.net { method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public android.telephony.SubscriptionPlan getSubscriptionPlan(@NonNull android.net.NetworkTemplate); method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean); method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidRestrictedOnMeteredNetworks(int); - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderWarningOrLimitReached(); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderLimitReached(); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderWarningReached(); method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void registerNetworkPolicyCallback(@Nullable java.util.concurrent.Executor, @NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback); method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void unregisterNetworkPolicyCallback(@NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback); } diff --git a/core/api/system-current.txt b/core/api/system-current.txt index bb9af143b4b4..6145886a47e4 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -7063,45 +7063,6 @@ package android.metrics { package android.net { - public class EthernetManager { - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void connectNetwork(@NonNull String, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.BiConsumer<android.net.Network,android.net.EthernetNetworkManagementException>); - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void disconnectNetwork(@NonNull String, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.BiConsumer<android.net.Network,android.net.EthernetNetworkManagementException>); - method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull java.util.concurrent.Executor, @NonNull android.net.EthernetManager.TetheredInterfaceCallback); - method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void updateConfiguration(@NonNull String, @NonNull android.net.EthernetNetworkUpdateRequest, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.BiConsumer<android.net.Network,android.net.EthernetNetworkManagementException>); - } - - public static interface EthernetManager.TetheredInterfaceCallback { - method public void onAvailable(@NonNull String); - method public void onUnavailable(); - } - - public static class EthernetManager.TetheredInterfaceRequest { - method public void release(); - } - - public final class EthernetNetworkManagementException extends java.lang.RuntimeException implements android.os.Parcelable { - ctor public EthernetNetworkManagementException(@NonNull String); - method public int describeContents(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkManagementException> CREATOR; - } - - public final class EthernetNetworkUpdateRequest implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public android.net.IpConfiguration getIpConfiguration(); - method @Nullable public android.net.NetworkCapabilities getNetworkCapabilities(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkUpdateRequest> CREATOR; - } - - public static final class EthernetNetworkUpdateRequest.Builder { - ctor public EthernetNetworkUpdateRequest.Builder(); - ctor public EthernetNetworkUpdateRequest.Builder(@NonNull android.net.EthernetNetworkUpdateRequest); - method @NonNull public android.net.EthernetNetworkUpdateRequest build(); - method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setIpConfiguration(@NonNull android.net.IpConfiguration); - method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setNetworkCapabilities(@Nullable android.net.NetworkCapabilities); - } - public final class MatchAllNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { ctor public MatchAllNetworkSpecifier(); method public int describeContents(); diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 6a0a2892cb96..aee66a29f278 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -125,8 +125,6 @@ import android.media.tv.tunerresourcemanager.ITunerResourceManager; import android.media.tv.tunerresourcemanager.TunerResourceManager; import android.net.ConnectivityFrameworkInitializer; import android.net.ConnectivityFrameworkInitializerTiramisu; -import android.net.EthernetManager; -import android.net.IEthernetManager; import android.net.INetworkPolicyManager; import android.net.IPacProxyManager; import android.net.IVpnManager; @@ -764,15 +762,6 @@ public final class SystemServiceRegistry { return new LowpanManager(ctx.getOuterContext(), service); }}); - registerService(Context.ETHERNET_SERVICE, EthernetManager.class, - new CachedServiceFetcher<EthernetManager>() { - @Override - public EthernetManager createService(ContextImpl ctx) throws ServiceNotFoundException { - IBinder b = ServiceManager.getServiceOrThrow(Context.ETHERNET_SERVICE); - IEthernetManager service = IEthernetManager.Stub.asInterface(b); - return new EthernetManager(ctx.getOuterContext(), service); - }}); - registerService(Context.WIFI_NL80211_SERVICE, WifiNl80211Manager.class, new CachedServiceFetcher<WifiNl80211Manager>() { @Override diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index 0e39f425c0fa..341d98f27320 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -558,6 +558,24 @@ public class NetworkPolicyManager { } /** + * Notifies that the specified {@link NetworkStatsProvider} has reached its warning threshold + * which was set through {@link NetworkStatsProvider#onSetWarningAndLimit(String, long, long)}. + * + * @hide + */ + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public void notifyStatsProviderWarningReached() { + try { + mService.notifyStatsProviderWarningOrLimitReached(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Notifies that the specified {@link NetworkStatsProvider} has reached its quota * which was set through {@link NetworkStatsProvider#onSetLimit(String, long)} or * {@link NetworkStatsProvider#onSetWarningAndLimit(String, long, long)}. @@ -568,7 +586,7 @@ public class NetworkPolicyManager { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public void notifyStatsProviderWarningOrLimitReached() { + public void notifyStatsProviderLimitReached() { try { mService.notifyStatsProviderWarningOrLimitReached(); } catch (RemoteException e) { diff --git a/packages/ConnectivityT/framework-t/Android.bp b/packages/ConnectivityT/framework-t/Android.bp index 66527802a0e4..217a1f67c336 100644 --- a/packages/ConnectivityT/framework-t/Android.bp +++ b/packages/ConnectivityT/framework-t/Android.bp @@ -154,17 +154,17 @@ filegroup { ], } +// TODO: remove this empty filegroup. filegroup { name: "framework-connectivity-tiramisu-sources", - srcs: [ - ":framework-connectivity-ethernet-sources", - ], + srcs: [], visibility: ["//frameworks/base"], } filegroup { name: "framework-connectivity-tiramisu-updatable-sources", srcs: [ + ":framework-connectivity-ethernet-sources", ":framework-connectivity-ipsec-sources", ":framework-connectivity-netstats-sources", ":framework-connectivity-nsd-sources", diff --git a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java index 9bffbfb27a8d..61b34d0bcfe6 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java +++ b/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java @@ -34,8 +34,9 @@ public final class ConnectivityFrameworkInitializerTiramisu { private ConnectivityFrameworkInitializerTiramisu() {} /** - * Called by {@link SystemServiceRegistry}'s static initializer and registers nsd services to - * {@link Context}, so that {@link Context#getSystemService} can return them. + * Called by {@link SystemServiceRegistry}'s static initializer and registers NetworkStats, nsd, + * ipsec and ethernet services to {@link Context}, so that {@link Context#getSystemService} can + * return them. * * @throws IllegalStateException if this is called anywhere besides * {@link SystemServiceRegistry}. @@ -68,5 +69,14 @@ public final class ConnectivityFrameworkInitializerTiramisu { return new NetworkStatsManager(context, service); } ); + + SystemServiceRegistry.registerContextAwareService( + Context.ETHERNET_SERVICE, + EthernetManager.class, + (context, serviceBinder) -> { + IEthernetManager service = IEthernetManager.Stub.asInterface(serviceBinder); + return new EthernetManager(context, service); + } + ); } } diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java index eba51c11487e..793f28d5aa59 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java +++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java @@ -33,7 +33,7 @@ import android.os.Build; import android.os.RemoteException; import com.android.internal.annotations.GuardedBy; -import com.android.internal.os.BackgroundThread; +import com.android.modules.utils.BackgroundThread; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl index 7eaa01e262fe..01ff02dfc5b3 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl +++ b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl @@ -26,6 +26,7 @@ import android.net.NetworkStats; oneway interface INetworkStatsProviderCallback { void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); void notifyAlertReached(); - void notifyWarningOrLimitReached(); + void notifyWarningReached(); + void notifyLimitReached(); void unregister(); } diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java index 23fc06927ef9..d37a53dbf1e9 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java +++ b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java @@ -152,19 +152,19 @@ public abstract class NetworkStatsProvider { try { // Reuse the code path to notify warning reached with limit reached // since framework handles them in the same way. - getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached(); + getProviderCallbackBinderOrThrow().notifyWarningReached(); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } } /** - * Notify system that the quota set by {@link #onSetLimit} or limit set by + * Notify system that the limit set by {@link #onSetLimit} or limit set by * {@link #onSetWarningAndLimit} has been reached. */ public void notifyLimitReached() { try { - getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached(); + getProviderCallbackBinderOrThrow().notifyLimitReached(); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } diff --git a/packages/ConnectivityT/service/Android.bp b/packages/ConnectivityT/service/Android.bp index 5100e7c5b9a4..4b799c599be9 100644 --- a/packages/ConnectivityT/service/Android.bp +++ b/packages/ConnectivityT/service/Android.bp @@ -102,17 +102,16 @@ filegroup { ], path: "src", visibility: [ - "//frameworks/opt/net/ethernet", + "//frameworks/opt/net/ethernet/tests", ], } // Connectivity-T common libraries. +// TODO: remove this empty filegroup. filegroup { name: "services.connectivity-tiramisu-sources", - srcs: [ - ":services.connectivity-ethernet-sources", - ], + srcs: [], path: "src", visibility: ["//frameworks/base/services/core"], } @@ -120,6 +119,7 @@ filegroup { filegroup { name: "services.connectivity-tiramisu-updatable-sources", srcs: [ + ":services.connectivity-ethernet-sources", ":services.connectivity-ipsec-sources", ":services.connectivity-netstats-sources", ":services.connectivity-nsd-sources", diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java index 3db635b1d503..7db4b8c849d6 100644 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java +++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java @@ -2393,10 +2393,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void notifyWarningOrLimitReached() { - Log.d(TAG, mTag + ": notifyWarningOrLimitReached"); + public void notifyWarningReached() { + Log.d(TAG, mTag + ": notifyWarningReached"); BinderUtils.withCleanCallingIdentity(() -> - mNetworkPolicyManager.notifyStatsProviderWarningOrLimitReached()); + mNetworkPolicyManager.notifyStatsProviderWarningReached()); + } + + @Override + public void notifyLimitReached() { + Log.d(TAG, mTag + ": notifyLimitReached"); + BinderUtils.withCleanCallingIdentity(() -> + mNetworkPolicyManager.notifyStatsProviderLimitReached()); } @Override diff --git a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java b/packages/ConnectivityT/tests/unit/java/com/android/server/net/IpConfigStoreTest.java index 2f771260ac1b..ad0be5862c5d 100644 --- a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java +++ b/packages/ConnectivityT/tests/unit/java/com/android/server/net/IpConfigStoreTest.java @@ -48,10 +48,16 @@ import java.util.Arrays; */ @RunWith(AndroidJUnit4.class) public class IpConfigStoreTest { + private static final int KEY_CONFIG = 17; + private static final String IFACE_1 = "eth0"; + private static final String IFACE_2 = "eth1"; + private static final String IP_ADDR_1 = "192.168.1.10/24"; + private static final String IP_ADDR_2 = "192.168.1.20/24"; + private static final String DNS_IP_ADDR_1 = "1.2.3.4"; + private static final String DNS_IP_ADDR_2 = "5.6.7.8"; @Test public void backwardCompatibility2to3() throws IOException { - final int KEY_CONFIG = 17; ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); DataOutputStream outputStream = new DataOutputStream(byteStream); @@ -73,13 +79,6 @@ public class IpConfigStoreTest { @Test public void staticIpMultiNetworks() throws Exception { - final String IFACE_1 = "eth0"; - final String IFACE_2 = "eth1"; - final String IP_ADDR_1 = "192.168.1.10/24"; - final String IP_ADDR_2 = "192.168.1.20/24"; - final String DNS_IP_ADDR_1 = "1.2.3.4"; - final String DNS_IP_ADDR_2 = "5.6.7.8"; - final ArrayList<InetAddress> dnsServers = new ArrayList<>(); dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_1)); dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_2)); @@ -144,11 +143,11 @@ public class IpConfigStoreTest { /** Synchronously writes into given byte steam */ private static class MockedDelayedDiskWrite extends DelayedDiskWrite { - final ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + final ByteArrayOutputStream mByteStream = new ByteArrayOutputStream(); @Override public void write(String filePath, Writer w) { - DataOutputStream outputStream = new DataOutputStream(byteStream); + DataOutputStream outputStream = new DataOutputStream(mByteStream); try { w.onWriteCalled(outputStream); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java index 68dcdd9ff49f..7de6a0e5e7cc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java @@ -186,7 +186,7 @@ public class StatusBarMobileView extends FrameLayout implements DarkReceiver, setContentDescription(state.contentDescription); int newVisibility = state.visible && !mForceHidden ? View.VISIBLE : View.GONE; - if (newVisibility != mMobileGroup.getVisibility()) { + if (newVisibility != mMobileGroup.getVisibility() && STATE_ICON == mVisibleState) { mMobileGroup.setVisibility(newVisibility); needsLayout = true; } diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index b6b54fc19011..c3e0290fb530 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -200,6 +200,10 @@ public final class NotificationRecord { private boolean mIsAppImportanceLocked; private ArraySet<Uri> mGrantableUris; + // Storage for phone numbers that were found to be associated with + // contacts in this notification. + private ArraySet<String> mPhoneNumbers; + // Whether this notification record should have an update logged the next time notifications // are sorted. private boolean mPendingLogUpdate = false; @@ -1525,6 +1529,26 @@ public final class NotificationRecord { return mPendingLogUpdate; } + /** + * Merge the given set of phone numbers into the list of phone numbers that + * are cached on this notification record. + */ + public void mergePhoneNumbers(ArraySet<String> phoneNumbers) { + // if the given phone numbers are null or empty then don't do anything + if (phoneNumbers == null || phoneNumbers.size() == 0) { + return; + } + // initialize if not already + if (mPhoneNumbers == null) { + mPhoneNumbers = new ArraySet<>(); + } + mPhoneNumbers.addAll(phoneNumbers); + } + + public ArraySet<String> getPhoneNumbers() { + return mPhoneNumbers; + } + @VisibleForTesting static final class Light { public final int color; diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java index d7bc3bb8af28..dc4d04feab72 100644 --- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java +++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java @@ -68,7 +68,10 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { private static final boolean ENABLE_PEOPLE_VALIDATOR = true; private static final String SETTING_ENABLE_PEOPLE_VALIDATOR = "validate_notification_people_enabled"; - private static final String[] LOOKUP_PROJECTION = { Contacts._ID, Contacts.STARRED }; + private static final String[] LOOKUP_PROJECTION = { Contacts._ID, Contacts.LOOKUP_KEY, + Contacts.STARRED, Contacts.HAS_PHONE_NUMBER }; + private static final String[] PHONE_LOOKUP_PROJECTION = + { ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER }; private static final int MAX_PEOPLE = 10; private static final int PEOPLE_CACHE_SIZE = 200; @@ -409,6 +412,35 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { return lookupResult; } + @VisibleForTesting + // Performs a contacts search using searchContacts, and then follows up by looking up + // any phone numbers associated with the resulting contact information and merge those + // into the lookup result as well. Will have no additional effect if the contact does + // not have any phone numbers. + LookupResult searchContactsAndLookupNumbers(Context context, Uri lookupUri) { + LookupResult lookupResult = searchContacts(context, lookupUri); + String phoneLookupKey = lookupResult.getPhoneLookupKey(); + if (phoneLookupKey != null) { + String selection = Contacts.LOOKUP_KEY + " = ?"; + String[] selectionArgs = new String[] { phoneLookupKey }; + try (Cursor cursor = context.getContentResolver().query( + ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PHONE_LOOKUP_PROJECTION, + selection, selectionArgs, /* sortOrder= */ null)) { + if (cursor == null) { + Slog.w(TAG, "Cursor is null when querying contact phone number."); + return lookupResult; + } + + while (cursor.moveToNext()) { + lookupResult.mergePhoneNumber(cursor); + } + } catch (Throwable t) { + Slog.w(TAG, "Problem getting content resolver or querying phone numbers.", t); + } + } + return lookupResult; + } + private void addWorkContacts(LookupResult lookupResult, Context context, Uri corpLookupUri) { final int workUserId = findWorkUserId(context); if (workUserId == -1) { @@ -454,6 +486,9 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { private final long mExpireMillis; private float mAffinity = NONE; + private boolean mHasPhone = false; + private String mPhoneLookupKey = null; + private ArraySet<String> mPhoneNumbers = new ArraySet<>(); public LookupResult() { mExpireMillis = System.currentTimeMillis() + CONTACT_REFRESH_MILLIS; @@ -473,6 +508,15 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { Slog.i(TAG, "invalid cursor: no _ID"); } + // Lookup key for potentially looking up contact phone number later + final int lookupKeyIdx = cursor.getColumnIndex(Contacts.LOOKUP_KEY); + if (lookupKeyIdx >= 0) { + mPhoneLookupKey = cursor.getString(lookupKeyIdx); + if (DEBUG) Slog.d(TAG, "contact LOOKUP_KEY is: " + mPhoneLookupKey); + } else { + if (DEBUG) Slog.d(TAG, "invalid cursor: no LOOKUP_KEY"); + } + // Starred final int starIdx = cursor.getColumnIndex(Contacts.STARRED); if (starIdx >= 0) { @@ -484,6 +528,39 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { } else { if (DEBUG) Slog.d(TAG, "invalid cursor: no STARRED"); } + + // whether a phone number is present + final int hasPhoneIdx = cursor.getColumnIndex(Contacts.HAS_PHONE_NUMBER); + if (hasPhoneIdx >= 0) { + mHasPhone = cursor.getInt(hasPhoneIdx) != 0; + if (DEBUG) Slog.d(TAG, "contact HAS_PHONE_NUMBER is: " + mHasPhone); + } else { + if (DEBUG) Slog.d(TAG, "invalid cursor: no HAS_PHONE_NUMBER"); + } + } + + // Returns the phone lookup key that is cached in this result, or null + // if the contact has no known phone info. + public String getPhoneLookupKey() { + if (!mHasPhone) { + return null; + } + return mPhoneLookupKey; + } + + // Merge phone number found in this lookup and store it in mPhoneNumbers. + public void mergePhoneNumber(Cursor cursor) { + final int phoneNumIdx = cursor.getColumnIndex( + ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER); + if (phoneNumIdx >= 0) { + mPhoneNumbers.add(cursor.getString(phoneNumIdx)); + } else { + if (DEBUG) Slog.d(TAG, "invalid cursor: no NORMALIZED_NUMBER"); + } + } + + public ArraySet<String> getPhoneNumbers() { + return mPhoneNumbers; } private boolean isExpired() { @@ -509,6 +586,7 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { // Amount of time to wait for a result from the contacts db before rechecking affinity. private static final long LOOKUP_TIME = 1000; private float mContactAffinity = NONE; + private ArraySet<String> mPhoneNumbers = null; private NotificationRecord mRecord; private PeopleRankingReconsideration(Context context, String key, @@ -543,7 +621,9 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { lookupResult = resolveEmailContact(mContext, uri.getSchemeSpecificPart()); } else if (handle.startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) { if (DEBUG) Slog.d(TAG, "checking lookup URI: " + handle); - lookupResult = searchContacts(mContext, uri); + // only look up phone number if this is a contact lookup uri and thus isn't + // already directly a phone number. + lookupResult = searchContactsAndLookupNumbers(mContext, uri); } else { lookupResult = new LookupResult(); // invalid person for the cache if (!"name".equals(uri.getScheme())) { @@ -561,6 +641,13 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { Slog.d(TAG, "lookup contactAffinity is " + lookupResult.getAffinity()); } mContactAffinity = Math.max(mContactAffinity, lookupResult.getAffinity()); + // merge any phone numbers found in this lookup result + if (lookupResult.getPhoneNumbers() != null) { + if (mPhoneNumbers == null) { + mPhoneNumbers = new ArraySet<>(); + } + mPhoneNumbers.addAll(lookupResult.getPhoneNumbers()); + } } else { if (DEBUG) Slog.d(TAG, "lookupResult is null"); } @@ -581,6 +668,7 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { float affinityBound = operand.getContactAffinity(); operand.setContactAffinity(Math.max(mContactAffinity, affinityBound)); if (VERBOSE) Slog.i(TAG, "final affinity: " + operand.getContactAffinity()); + operand.mergePhoneNumbers(mPhoneNumbers); } public float getContactAffinity() { diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java index acbe04b8c519..f9a7c4658245 100644 --- a/services/core/java/com/android/server/notification/ZenModeFiltering.java +++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java @@ -33,6 +33,7 @@ import android.telecom.TelecomManager; import android.telephony.PhoneNumberUtils; import android.telephony.TelephonyManager; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Slog; import com.android.internal.messages.nano.SystemMessageProto; @@ -126,7 +127,7 @@ public class ZenModeFiltering { } protected void recordCall(NotificationRecord record) { - REPEAT_CALLERS.recordCall(mContext, extras(record)); + REPEAT_CALLERS.recordCall(mContext, extras(record), record.getPhoneNumbers()); } /** @@ -325,6 +326,10 @@ public class ZenModeFiltering { } } + protected void cleanUpCallersAfter(long timeThreshold) { + REPEAT_CALLERS.cleanUpCallsAfter(timeThreshold); + } + private static class RepeatCallers { // We keep a separate map per uri scheme to do more generous number-matching // handling on telephone numbers specifically. For other inputs, we @@ -333,7 +338,8 @@ public class ZenModeFiltering { private final ArrayMap<String, Long> mOtherCalls = new ArrayMap<>(); private int mThresholdMinutes; - private synchronized void recordCall(Context context, Bundle extras) { + private synchronized void recordCall(Context context, Bundle extras, + ArraySet<String> phoneNumbers) { setThresholdMinutes(context); if (mThresholdMinutes <= 0 || extras == null) return; final String[] extraPeople = ValidateNotificationPeople.getExtraPeople(extras); @@ -341,7 +347,7 @@ public class ZenModeFiltering { final long now = System.currentTimeMillis(); cleanUp(mTelCalls, now); cleanUp(mOtherCalls, now); - recordCallers(extraPeople, now); + recordCallers(extraPeople, phoneNumbers, now); } private synchronized boolean isRepeat(Context context, Bundle extras) { @@ -365,6 +371,23 @@ public class ZenModeFiltering { } } + // Clean up all calls that occurred after the given time. + // Used only for tests, to clean up after testing. + private synchronized void cleanUpCallsAfter(long timeThreshold) { + for (int i = mTelCalls.size() - 1; i >= 0; i--) { + final long time = mTelCalls.valueAt(i); + if (time > timeThreshold) { + mTelCalls.removeAt(i); + } + } + for (int j = mOtherCalls.size() - 1; j >= 0; j--) { + final long time = mOtherCalls.valueAt(j); + if (time > timeThreshold) { + mOtherCalls.removeAt(j); + } + } + } + private void setThresholdMinutes(Context context) { if (mThresholdMinutes <= 0) { mThresholdMinutes = context.getResources().getInteger(com.android.internal.R.integer @@ -372,7 +395,8 @@ public class ZenModeFiltering { } } - private synchronized void recordCallers(String[] people, long now) { + private synchronized void recordCallers(String[] people, ArraySet<String> phoneNumbers, + long now) { for (int i = 0; i < people.length; i++) { String person = people[i]; if (person == null) continue; @@ -393,6 +417,14 @@ public class ZenModeFiltering { mOtherCalls.put(person, now); } } + + // record any additional numbers from the notification record if + // provided; these are in the format of just a phone number string + if (phoneNumbers != null) { + for (String num : phoneNumbers) { + mTelCalls.put(num, now); + } + } } private synchronized boolean checkCallers(Context context, String[] people) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index c3197faec9c3..153d068d2551 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -17877,14 +17877,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } else { preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT); } - List<Integer> allowedUids = Arrays.stream( - preferentialNetworkServiceConfig.getIncludedUids()).boxed().collect( - Collectors.toList()); - List<Integer> excludedUids = Arrays.stream( - preferentialNetworkServiceConfig.getExcludedUids()).boxed().collect( - Collectors.toList()); - preferenceBuilder.setIncludedUids(allowedUids); - preferenceBuilder.setExcludedUids(excludedUids); + preferenceBuilder.setIncludedUids(preferentialNetworkServiceConfig.getIncludedUids()); + preferenceBuilder.setExcludedUids(preferentialNetworkServiceConfig.getExcludedUids()); preferenceBuilder.setPreferenceEnterpriseId( preferentialNetworkServiceConfig.getNetworkId()); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 5ae8a5abd6eb..67b656bf2bfc 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -283,8 +283,6 @@ public final class SystemServer implements Dumpable { "com.android.server.wifi.p2p.WifiP2pService"; private static final String LOWPAN_SERVICE_CLASS = "com.android.server.lowpan.LowpanService"; - private static final String ETHERNET_SERVICE_CLASS = - "com.android.server.ethernet.EthernetService"; private static final String JOB_SCHEDULER_SERVICE_CLASS = "com.android.server.job.JobSchedulerService"; private static final String LOCK_SETTINGS_SERVICE_CLASS = @@ -1889,13 +1887,6 @@ public final class SystemServer implements Dumpable { t.traceEnd(); } - if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) || - mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) { - t.traceBegin("StartEthernet"); - mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS); - t.traceEnd(); - } - t.traceBegin("StartPacProxyService"); try { pacProxyService = new PacProxyService(context); 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 a67751d5b4bc..8225ae6071de 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -4240,14 +4240,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setPreferentialNetworkServiceConfigs(List.of(preferentialNetworkServiceConfigEnabled)); assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0) .isEnabled()).isTrue(); - List<Integer> includedList = new ArrayList<>(); - includedList.add(1); - includedList.add(2); ProfileNetworkPreference preferenceDetails = new ProfileNetworkPreference.Builder() .setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK) .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1) - .setIncludedUids(includedList) + .setIncludedUids(new int[]{1, 2}) .build(); List<ProfileNetworkPreference> preferences = new ArrayList<>(); preferences.add(preferenceDetails); @@ -4275,14 +4272,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setPreferentialNetworkServiceConfigs(List.of(preferentialNetworkServiceConfigEnabled)); assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0) .isEnabled()).isTrue(); - List<Integer> excludedUids = new ArrayList<>(); - excludedUids.add(1); - excludedUids.add(2); ProfileNetworkPreference preferenceDetails = new ProfileNetworkPreference.Builder() .setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK) .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1) - .setExcludedUids(excludedUids) + .setExcludedUids(new int[]{1, 2}) .build(); List<ProfileNetworkPreference> preferences = new ArrayList<>(); preferences.clear(); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java index 49b63863fec7..dfd8f48460c0 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java @@ -66,6 +66,7 @@ import android.os.Vibrator; import android.provider.Settings; import android.service.notification.Adjustment; import android.service.notification.StatusBarNotification; +import android.util.ArraySet; import android.widget.RemoteViews; import androidx.test.filters.SmallTest; @@ -1328,4 +1329,45 @@ public class NotificationRecordTest extends UiServiceTestCase { assertFalse(record.isConversation()); } + + @Test + public void mergePhoneNumbers_nulls() { + // make sure nothing dies if we just don't have any phone numbers + StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, + false /* lights */, false /* defaultLights */, null /* group */); + NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel); + + // by default, no phone numbers + assertNull(record.getPhoneNumbers()); + + // nothing happens if we attempt to merge phone numbers but there aren't any + record.mergePhoneNumbers(null); + assertNull(record.getPhoneNumbers()); + } + + @Test + public void mergePhoneNumbers_addNumbers() { + StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, + false /* lights */, false /* defaultLights */, null /* group */); + NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel); + + // by default, no phone numbers + assertNull(record.getPhoneNumbers()); + + // make sure it behaves properly when we merge in some real content + record.mergePhoneNumbers(new ArraySet<>( + new String[]{"16175551212", "16175552121"})); + assertTrue(record.getPhoneNumbers().contains("16175551212")); + assertTrue(record.getPhoneNumbers().contains("16175552121")); + assertFalse(record.getPhoneNumbers().contains("16175553434")); + + // now merge in a new number, make sure old ones are still there and the new one + // is also there + record.mergePhoneNumbers(new ArraySet<>(new String[]{"16175553434"})); + assertTrue(record.getPhoneNumbers().contains("16175551212")); + assertTrue(record.getPhoneNumbers().contains("16175552121")); + assertTrue(record.getPhoneNumbers().contains("16175553434")); + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java index 0bf105d62053..0552a8350329 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java @@ -19,8 +19,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.contains; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -29,6 +34,7 @@ import android.app.Person; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; +import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.UserManager; @@ -43,6 +49,8 @@ import com.android.server.UiServiceTestCase; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import java.util.ArrayList; import java.util.Arrays; @@ -240,6 +248,118 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase { assertFalse(ContentProvider.uriHasUserId(queryUri.getValue())); } + @Test + public void testMergePhoneNumbers_noPhoneNumber() { + // If merge phone number is called but the contacts lookup turned up no available + // phone number (HAS_PHONE_NUMBER is false), then no query should happen. + + // setup of various bits required for querying + final Context mockContext = mock(Context.class); + final ContentResolver mockContentResolver = mock(ContentResolver.class); + when(mockContext.getContentResolver()).thenReturn(mockContentResolver); + final int contactId = 12345; + final Uri lookupUri = Uri.withAppendedPath( + ContactsContract.Contacts.CONTENT_LOOKUP_URI, String.valueOf(contactId)); + + // when the contact is looked up, we return a cursor that has one entry whose info is: + // _ID: 1 + // LOOKUP_KEY: "testlookupkey" + // STARRED: 0 + // HAS_PHONE_NUMBER: 0 + Cursor cursor = makeMockCursor(1, "testlookupkey", 0, 0); + when(mockContentResolver.query(any(), any(), any(), any(), any())).thenReturn(cursor); + + // call searchContacts and then mergePhoneNumbers, make sure we never actually + // query the content resolver for a phone number + new ValidateNotificationPeople().searchContactsAndLookupNumbers(mockContext, lookupUri); + verify(mockContentResolver, never()).query( + eq(ContactsContract.CommonDataKinds.Phone.CONTENT_URI), + eq(new String[] { ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER }), + contains(ContactsContract.Contacts.LOOKUP_KEY), + any(), // selection args + isNull()); // sort order + } + + @Test + public void testMergePhoneNumbers_hasNumber() { + // If merge phone number is called and the contact lookup has a phone number, + // make sure there's then a subsequent query for the phone number. + + // setup of various bits required for querying + final Context mockContext = mock(Context.class); + final ContentResolver mockContentResolver = mock(ContentResolver.class); + when(mockContext.getContentResolver()).thenReturn(mockContentResolver); + final int contactId = 12345; + final Uri lookupUri = Uri.withAppendedPath( + ContactsContract.Contacts.CONTENT_LOOKUP_URI, String.valueOf(contactId)); + + // when the contact is looked up, we return a cursor that has one entry whose info is: + // _ID: 1 + // LOOKUP_KEY: "testlookupkey" + // STARRED: 0 + // HAS_PHONE_NUMBER: 1 + Cursor cursor = makeMockCursor(1, "testlookupkey", 0, 1); + + // make sure to add some specifics so this cursor is only returned for the + // contacts database lookup. + when(mockContentResolver.query(eq(lookupUri), any(), + isNull(), isNull(), isNull())).thenReturn(cursor); + + // in the case of a phone lookup, return null cursor; that's not an error case + // and we're not checking the actual storing of the phone data here. + when(mockContentResolver.query(eq(ContactsContract.CommonDataKinds.Phone.CONTENT_URI), + eq(new String[] { ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER }), + contains(ContactsContract.Contacts.LOOKUP_KEY), + any(), isNull())).thenReturn(null); + + // call searchContacts and then mergePhoneNumbers, and check that we query + // once for the + new ValidateNotificationPeople().searchContactsAndLookupNumbers(mockContext, lookupUri); + verify(mockContentResolver, times(1)).query( + eq(ContactsContract.CommonDataKinds.Phone.CONTENT_URI), + eq(new String[] { ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER }), + contains(ContactsContract.Contacts.LOOKUP_KEY), + eq(new String[] { "testlookupkey" }), // selection args + isNull()); // sort order + } + + // Creates a cursor that points to one item of Contacts data with the specified + // columns. + private Cursor makeMockCursor(int id, String lookupKey, int starred, int hasPhone) { + Cursor mockCursor = mock(Cursor.class); + when(mockCursor.moveToFirst()).thenReturn(true); + doAnswer(new Answer<Boolean>() { + boolean mAccessed = false; + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + if (!mAccessed) { + mAccessed = true; + return true; + } + return false; + } + + }).when(mockCursor).moveToNext(); + + // id + when(mockCursor.getColumnIndex(ContactsContract.Contacts._ID)).thenReturn(0); + when(mockCursor.getInt(0)).thenReturn(id); + + // lookup key + when(mockCursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)).thenReturn(1); + when(mockCursor.getString(1)).thenReturn(lookupKey); + + // starred + when(mockCursor.getColumnIndex(ContactsContract.Contacts.STARRED)).thenReturn(2); + when(mockCursor.getInt(2)).thenReturn(starred); + + // has phone number + when(mockCursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)).thenReturn(3); + when(mockCursor.getInt(3)).thenReturn(hasPhone); + + return mockCursor; + } + private void assertStringArrayEquals(String message, String[] expected, String[] result) { String expectedString = Arrays.toString(expected); String resultString = Arrays.toString(result); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java index 0f18cc61a95a..abcc8c1e99cb 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java @@ -50,11 +50,13 @@ import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.util.ArraySet; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.util.NotificationMessagingUtil; import com.android.server.UiServiceTestCase; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -72,6 +74,8 @@ public class ZenModeFilteringTest extends UiServiceTestCase { @Mock private TelephonyManager mTelephonyManager; + private long mTestStartTime; + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -79,6 +83,13 @@ public class ZenModeFilteringTest extends UiServiceTestCase { // for repeat callers / matchesCallFilter mContext.addMockSystemService(TelephonyManager.class, mTelephonyManager); + mTestStartTime = System.currentTimeMillis(); + } + + @After + public void tearDown() { + // make sure to get rid of any data stored in repeat callers + mZenModeFiltering.cleanUpCallersAfter(mTestStartTime); } private NotificationRecord getNotificationRecord() { @@ -108,7 +119,10 @@ public class ZenModeFilteringTest extends UiServiceTestCase { return extras; } - private NotificationRecord getNotificationRecordWithPeople(String[] people) { + // Create a notification record with the people String array as the + // bundled extras, and the numbers ArraySet as additional phone numbers. + private NotificationRecord getRecordWithPeopleInfo(String[] people, + ArraySet<String> numbers) { // set up notification record NotificationRecord r = mock(NotificationRecord.class); StatusBarNotification sbn = mock(StatusBarNotification.class); @@ -116,6 +130,7 @@ public class ZenModeFilteringTest extends UiServiceTestCase { notification.extras = makeExtrasBundleWithPeople(people); when(sbn.getNotification()).thenReturn(notification); when(r.getSbn()).thenReturn(sbn); + when(r.getPhoneNumbers()).thenReturn(numbers); return r; } @@ -339,7 +354,7 @@ public class ZenModeFilteringTest extends UiServiceTestCase { // after calls given an email with an exact string match, make sure that // matchesCallFilter returns the right thing String[] mailSource = new String[]{"mailto:hello.world"}; - mZenModeFiltering.recordCall(getNotificationRecordWithPeople(mailSource)); + mZenModeFiltering.recordCall(getRecordWithPeopleInfo(mailSource, null)); // set up policy to only allow repeat callers Policy policy = new Policy( @@ -362,7 +377,7 @@ public class ZenModeFilteringTest extends UiServiceTestCase { when(mTelephonyManager.getNetworkCountryIso()).thenReturn("us"); String[] telSource = new String[]{"tel:+1-617-555-1212"}; - mZenModeFiltering.recordCall(getNotificationRecordWithPeople(telSource)); + mZenModeFiltering.recordCall(getRecordWithPeopleInfo(telSource, null)); // set up policy to only allow repeat callers Policy policy = new Policy( @@ -406,7 +421,7 @@ public class ZenModeFilteringTest extends UiServiceTestCase { when(mTelephonyManager.getNetworkCountryIso()).thenReturn("us"); String[] telSource = new String[]{"tel:%2B16175551212"}; - mZenModeFiltering.recordCall(getNotificationRecordWithPeople(telSource)); + mZenModeFiltering.recordCall(getRecordWithPeopleInfo(telSource, null)); // set up policy to only allow repeat callers Policy policy = new Policy( @@ -419,25 +434,64 @@ public class ZenModeFilteringTest extends UiServiceTestCase { Bundle different1 = makeExtrasBundleWithPeople(new String[]{"tel:%2B16175553434"}); Bundle different2 = makeExtrasBundleWithPeople(new String[]{"tel:+16175553434"}); - assertTrue("same number should match", + assertTrue("same number 1 should match", ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS, policy, UserHandle.SYSTEM, same1, null, 0, 0)); - assertTrue("same number should match", + assertTrue("same number 2 should match", ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS, policy, UserHandle.SYSTEM, same2, null, 0, 0)); - assertTrue("same number should match", + assertTrue("same number 3 should match", ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS, policy, UserHandle.SYSTEM, same3, null, 0, 0)); - assertFalse("different number should not match", + assertFalse("different number 1 should not match", ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS, policy, UserHandle.SYSTEM, different1, null, 0, 0)); - assertFalse("different number should not match", + assertFalse("different number 2 should not match", ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS, policy, UserHandle.SYSTEM, different2, null, 0, 0)); } + + @Test + public void testMatchesCallFilter_repeatCallers_viaRecordPhoneNumbers() { + // make sure that phone numbers that are passed in via the NotificationRecord's + // cached phone numbers field (from a contact lookup if the record is provided a contact + // uri) also get recorded in the repeat callers list. + + // set up telephony manager behavior + when(mTelephonyManager.getNetworkCountryIso()).thenReturn("us"); + + String[] contactSource = new String[]{"content://contacts/lookup/uri-here"}; + ArraySet<String> contactNumbers = new ArraySet<>( + new String[]{"1-617-555-1212", "1-617-555-3434"}); + NotificationRecord record = getRecordWithPeopleInfo(contactSource, contactNumbers); + record.mergePhoneNumbers(contactNumbers); + mZenModeFiltering.recordCall(record); + + // set up policy to only allow repeat callers + Policy policy = new Policy( + PRIORITY_CATEGORY_REPEAT_CALLERS, 0, 0, 0, CONVERSATION_SENDERS_NONE); + + // both phone numbers should register here + Bundle tel1 = makeExtrasBundleWithPeople(new String[]{"tel:+1-617-555-1212"}); + Bundle tel2 = makeExtrasBundleWithPeople(new String[]{"tel:16175553434"}); + Bundle different = makeExtrasBundleWithPeople(new String[]{"tel:16175555656"}); + + assertTrue("contact number 1 should match", + ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS, + policy, UserHandle.SYSTEM, + tel1, null, 0, 0)); + assertTrue("contact number 2 should match", + ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS, + policy, UserHandle.SYSTEM, + tel2, null, 0, 0)); + assertFalse("different number should not match", + ZenModeFiltering.matchesCallFilter(mContext, ZEN_MODE_IMPORTANT_INTERRUPTIONS, + policy, UserHandle.SYSTEM, + different, null, 0, 0)); + } } diff --git a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java index fe4453081362..5ffee5638cfa 100644 --- a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java +++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java @@ -32,7 +32,12 @@ import java.util.List; import java.util.Objects; /** - * Provides Qos attributes of an EPS bearer. + * Provides QOS attributes of an EPS bearer. + * + * <p> The dedicated EPS bearer along with QOS is allocated by the LTE network and notified to the + * device. The Telephony framework creates the {@link EpsBearerQosSessionAttributes} object which + * represents the QOS of the dedicated bearer and notifies the same to applications via + * {@link QosCallback}. * * {@hide} */ |